From d37c099060119f8ead81bfbf2c350951acf7d37c Mon Sep 17 00:00:00 2001 From: Dark98 Date: Thu, 5 Feb 2026 21:41:21 +0000 Subject: [PATCH] Cloud/Backend Overhaul Reverse Engineered a Backend Removed Boosty Stuff Removed Socials Stuff Removed Subscription Stuff Probably Some More --- app/build.gradle | 8 +- app/src/main/AndroidManifest.xml | 10 +- .../com/dark98/santoku/BeamServerData.java | 98 ---- .../java/com/dark98/santoku/MainActivity.java | 153 +----- .../main/java/com/dark98/santoku/Santoku.java | 3 - .../com/dark98/santoku/SetupActivity.java | 496 ++++++------------ .../santoku/boot/BeamServerDataTask.java | 25 - .../com/dark98/santoku/cloud/CloudAPI.java | 111 +--- .../dark98/santoku/cloud/CloudController.java | 87 +-- .../components/ChangeLogBottomSheet.java | 146 +----- .../components/CloudManageBottomSheet.java | 118 ++--- .../santoku/components/bed_menu/FileMenu.java | 189 +------ .../events/BeamServerDataUpdatedEvent.java | 6 - .../events/CloudFeaturesUpdatedEvent.java | 6 - ...CloudModelsRemainingCountUpdatedEvent.java | 6 - .../events/NeedDismissAIGeneratorMenu.java | 6 - .../santoku/fragment/SettingsFragment.java | 28 +- .../com/dark98/santoku/theme/BeamTheme.java | 5 - .../java/com/dark98/santoku/utils/Prefs.java | 59 --- .../dark98/santoku/view/BoostySubsView.java | 108 ---- app/src/main/res/drawable/boosty.xml | 23 - .../res/drawable/box_heart_outline_28.xml | 10 - app/src/main/res/drawable/k3d_logo_new_14.png | Bin 3923 -> 0 bytes app/src/main/res/drawable/telegram.xml | 10 - app/src/main/res/values-ru/strings.xml | 37 +- app/src/main/res/values/attrs.xml | 4 - app/src/main/res/values/strings.xml | 47 +- build.gradle | 133 ++++- 28 files changed, 431 insertions(+), 1501 deletions(-) delete mode 100644 app/src/main/java/com/dark98/santoku/BeamServerData.java delete mode 100644 app/src/main/java/com/dark98/santoku/boot/BeamServerDataTask.java delete mode 100644 app/src/main/java/com/dark98/santoku/events/BeamServerDataUpdatedEvent.java delete mode 100644 app/src/main/java/com/dark98/santoku/events/CloudFeaturesUpdatedEvent.java delete mode 100644 app/src/main/java/com/dark98/santoku/events/CloudModelsRemainingCountUpdatedEvent.java delete mode 100644 app/src/main/java/com/dark98/santoku/events/NeedDismissAIGeneratorMenu.java delete mode 100644 app/src/main/java/com/dark98/santoku/view/BoostySubsView.java delete mode 100644 app/src/main/res/drawable/boosty.xml delete mode 100644 app/src/main/res/drawable/box_heart_outline_28.xml delete mode 100644 app/src/main/res/drawable/k3d_logo_new_14.png delete mode 100644 app/src/main/res/drawable/telegram.xml diff --git a/app/build.gradle b/app/build.gradle index 9cb0891..45df293 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,6 +6,8 @@ plugins { } def commit = getGitCommitHash(file('.')) +def prodCloudBaseUrl = "https://santoku.dark98.co.uk/v1/" +def prodBeamBaseUrl = "https://santoku.dark98.co.uk" android { namespace 'com.dark98.santoku' @@ -16,9 +18,11 @@ android { minSdk 21 targetSdk 35 versionCode 8 - versionName "0.3.0" + versionName "0.0.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + buildConfigField "String", "CLOUD_BASE_URL_PROD", "\"" + prodCloudBaseUrl + "\"" + buildConfigField "String", "BEAM_BASE_URL_PROD", "\"" + prodBeamBaseUrl + "\"" externalNativeBuild { cmake { @@ -39,7 +43,6 @@ android { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - buildConfigField "boolean", "IS_GOOGLE_PLAY", "false" buildConfigField "String", "COMMIT", "\"" + commit + "\"" ndk { //noinspection ChromeOsAbiSupport @@ -47,7 +50,6 @@ android { } } debug { - buildConfigField "boolean", "IS_GOOGLE_PLAY", "false" buildConfigField "String", "COMMIT", "\"" + commit + "\"" ndk { debugSymbolLevel 'NONE' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 95b3449..acff79c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,9 +8,6 @@ - - - @@ -46,6 +43,13 @@ + + + + + + + diff --git a/app/src/main/java/com/dark98/santoku/BeamServerData.java b/app/src/main/java/com/dark98/santoku/BeamServerData.java deleted file mode 100644 index 7e0cb99..0000000 --- a/app/src/main/java/com/dark98/santoku/BeamServerData.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.dark98.santoku; - -import android.util.Log; - -import com.loopj.android.http.AsyncHttpClient; -import com.loopj.android.http.AsyncHttpResponseHandler; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import cz.msebera.android.httpclient.Header; -import com.dark98.santoku.cloud.CloudController; -import com.dark98.santoku.events.BeamServerDataUpdatedEvent; -import com.dark98.santoku.utils.Prefs; - -public class BeamServerData { - private final static String TAG = "BeamServerData"; - private final static String DATA_URL = "https://beam3d.ru/slicebeam.php?act=get_data"; - private final static String RUSSIA_CHECK_URL = "https://beam3d.ru/check_russia.txt"; - private static AsyncHttpClient client = new AsyncHttpClient(); - - static { - client.setUserAgent(String.format(Locale.ROOT, "Santoku/%s-%d", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); - client.setEnableRedirects(true); - client.setLoggingEnabled(false); - } - - public List boostySubscribers = new ArrayList<>(); - - public BeamServerData(JSONObject obj) { - JSONArray arr = obj.optJSONArray("boosty_subscribers"); - if (arr != null) { - for (int i = 0; i < arr.length(); i++) { - boostySubscribers.add(arr.optString(i)); - } - } - } - - public static boolean isBoostyAvailable() { - return !BuildConfig.IS_GOOGLE_PLAY || Prefs.isRussianIP(); - } - - public static boolean isCloudAvailable() { - return isBoostyAvailable() && CloudController.hasAccountFeatures(); - } - - public static void load() { - client.get(DATA_URL, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - String str = new String(responseBody, StandardCharsets.UTF_8); - Prefs.setBeamServerData(str); - Prefs.setLastCheckedInfo(); - - try { - Santoku.SERVER_DATA = new BeamServerData(new JSONObject(str)); - } catch (JSONException e) { - throw new RuntimeException(e); - } - - // Disable Boosty only for Google Play builds on non-Russian IP's - if (BuildConfig.IS_GOOGLE_PLAY) { - client.get(RUSSIA_CHECK_URL, new AsyncHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { - setIsRussia(new String(responseBody).equals("true")); - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - if (statusCode == 403) { - setIsRussia(false); - } - } - - private void setIsRussia(boolean v) { - Prefs.setRussianIP(v); - Santoku.EVENT_BUS.fireEvent(new BeamServerDataUpdatedEvent()); - } - }); - } else { - Santoku.EVENT_BUS.fireEvent(new BeamServerDataUpdatedEvent()); - } - } - - @Override - public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { - Log.e(TAG, "Failed to update server data", error); - } - }); - } -} diff --git a/app/src/main/java/com/dark98/santoku/MainActivity.java b/app/src/main/java/com/dark98/santoku/MainActivity.java index d5f5a80..c81d3ee 100644 --- a/app/src/main/java/com/dark98/santoku/MainActivity.java +++ b/app/src/main/java/com/dark98/santoku/MainActivity.java @@ -2,19 +2,13 @@ package com.dark98.santoku; import android.app.Activity; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Process; -import android.provider.MediaStore; -import android.util.Base64; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; @@ -32,7 +26,6 @@ import org.json.JSONArray; import org.json.JSONObject; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -48,14 +41,11 @@ import java.util.Objects; import java.util.UUID; import java.util.zip.ZipFile; -import ru.ytkab0bp.sapil.APICallback; -import com.dark98.santoku.cloud.CloudAPI; import com.dark98.santoku.cloud.CloudController; import com.dark98.santoku.components.BeamAlertDialogBuilder; import com.dark98.santoku.components.ChangeLogBottomSheet; import com.dark98.santoku.components.UnfoldMenu; import com.dark98.santoku.config.ConfigObject; -import com.dark98.santoku.events.NeedDismissAIGeneratorMenu; import com.dark98.santoku.events.NeedDismissSnackbarEvent; import com.dark98.santoku.events.NeedSnackbarEvent; import com.dark98.santoku.events.ObjectsListChangedEvent; @@ -76,8 +66,7 @@ public class MainActivity extends AppCompatActivity { // Activity result public final static int REQUEST_CODE_OPEN_FILE = 1, REQUEST_CODE_EXPORT_GCODE = 2, REQUEST_CODE_IMPORT_PROFILES = 3, REQUEST_CODE_EXPORT_PROFILES = 4, - REQUEST_CODE_EXPORT_3MF = 5, - REQUEST_CODE_AI_GENERATOR_TAKE_PHOTO = 6, REQUEST_CODE_AI_GENERATOR_CHOOSE_PHOTO = 7; + REQUEST_CODE_EXPORT_3MF = 5; private static MainActivity activeInstance; @@ -85,9 +74,6 @@ public class MainActivity extends AppCompatActivity { public static List EXPORTING_FILAMENTS; public static List EXPORTING_PRINTERS; - public static boolean IS_GENERATING_AI_MODEL; - - public static File aiTempFile; private static SparseArray liveDelegate = new SparseArray<>(); private static int lastId; @@ -154,8 +140,13 @@ public class MainActivity extends AppCompatActivity { setContentView(v); if (getIntent() != null && getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_VIEW)) { - loadFile(getIntent().getData()); - setIntent(null); + Uri data = getIntent().getData(); + if (data != null && "santoku".equalsIgnoreCase(data.getScheme())) { + setIntent(null); + } else { + loadFile(data); + setIntent(null); + } } DisplayMetrics dm = getResources().getDisplayMetrics(); @@ -196,7 +187,6 @@ public class MainActivity extends AppCompatActivity { if (!Objects.equals(Prefs.getLastCommit(), BuildConfig.COMMIT) && Santoku.hasUpdateInfo) { Prefs.setLastCommit(); - BeamServerData.load(); new ChangeLogBottomSheet(this).show(); } } @@ -209,7 +199,11 @@ public class MainActivity extends AppCompatActivity { @Override protected void onNewIntent(@NonNull Intent intent) { super.onNewIntent(intent); - loadFile(intent.getData()); + Uri data = intent.getData(); + if (data != null && "santoku".equalsIgnoreCase(data.getScheme())) { + return; + } + loadFile(data); setIntent(null); } @@ -327,23 +321,6 @@ public class MainActivity extends AppCompatActivity { .setPositiveButton(android.R.string.ok, null) .show(); } - } else if (requestCode == REQUEST_CODE_AI_GENERATOR_TAKE_PHOTO) { - Santoku.EVENT_BUS.fireEvent(new NeedDismissAIGeneratorMenu()); - - Bitmap bm = BitmapFactory.decodeFile(aiTempFile.getAbsolutePath()); - generateAiModel(bm); - aiTempFile.delete(); - aiTempFile = null; - } else if (requestCode == REQUEST_CODE_AI_GENERATOR_CHOOSE_PHOTO) { - Santoku.EVENT_BUS.fireEvent(new NeedDismissAIGeneratorMenu()); - - try { - InputStream in = getContentResolver().openInputStream(data.getData()); - Bitmap bm = BitmapFactory.decodeStream(in); - generateAiModel(bm); - } catch (Exception e) { - Log.e("ai_generator", "Failed to write to downloads", e); - } } } } @@ -490,110 +467,6 @@ public class MainActivity extends AppCompatActivity { }); } - private void generateAiModel(Bitmap bm) { - IS_GENERATING_AI_MODEL = true; - String uploadTag = UUID.randomUUID().toString(); - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuFileAIGeneratorUploading).tag(uploadTag)); - IOUtils.IO_POOL.submit(()->{ - Bitmap scaled; - if (bm.getWidth() > 1024 || bm.getHeight() > 1024) { - if (bm.getWidth() > bm.getHeight()) { - int w = 1024; - int h = (int) ((float) w * bm.getHeight() / bm.getWidth()); - scaled = Bitmap.createScaledBitmap(bm, w, h, true); - } else { - int h = 1024; - int w = (int) ((float) h * bm.getWidth() / bm.getHeight()); - scaled = Bitmap.createScaledBitmap(bm, w, h, true); - } - bm.recycle(); - } else { - scaled = bm; - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - scaled.compress(Bitmap.CompressFormat.PNG, 100, out); - scaled.recycle(); - - String processTag = UUID.randomUUID().toString(); - CloudAPI.INSTANCE.modelsGenerate(Base64.encodeToString(out.toByteArray(), Base64.NO_WRAP), "image/png", new APICallback() { - @Override - public void onResponse(InputStream in) { - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(processTag)); - - String downloadTag = UUID.randomUUID().toString(); - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuFileAIGeneratorDownloading).tag(downloadTag)); - String fileName = "generated_" + UUID.randomUUID() + ".stl"; - - File f = new File(Santoku.getModelCacheDir(), fileName); - try { - FileOutputStream fos = new FileOutputStream(f); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName); - contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "application/vnd.ms-pki.stl"); - contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS); - - Uri uri = getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues); - - if (uri != null) { - try { - OutputStream out = getContentResolver().openOutputStream(uri); - byte[] buf = new byte[10240]; - int c; - while ((c = in.read(buf)) != -1) { - out.write(buf, 0, c); - fos.write(buf, 0, c); - } - out.close(); - } catch (IOException e) { - Log.e("ai_generator", "Failed to write to downloads", e); - } - } - } else { - File downloadsDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); - File file = new File(downloadsDirectory, fileName); - - try { - FileOutputStream out = new FileOutputStream(file); - byte[] buf = new byte[10240]; - int c; - while ((c = in.read(buf)) != -1) { - out.write(buf, 0, c); - fos.write(buf, 0, c); - } - out.close(); - } catch (IOException e) { - Log.e("ai_generator", "Failed to write to downloads", e); - } - } - fos.close(); - } catch (Exception e) { - Log.e("ai_generator", "Failed to write to downloads", e); - } - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(downloadTag)); - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(R.string.MenuFileAIGeneratorSavedAs, fileName)); - loadFile(f, true); - CloudController.checkGeneratorRemaining(); - IS_GENERATING_AI_MODEL = false; - } - - @Override - public void onException(Exception e) { - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(processTag)); - ViewUtils.postOnMainThread(() -> new BeamAlertDialogBuilder(MainActivity.this) - .setTitle(R.string.MenuFileAIGeneratorError) - .setMessage(e.toString()) - .setPositiveButton(android.R.string.ok, null) - .show()); - IS_GENERATING_AI_MODEL = false; - } - }); - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(uploadTag)); - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuFileAIGeneratorProcessing).tag(processTag)); - }); - } - private void loadIniForImport(InputStream in) { IOUtils.IO_POOL.submit(()->{ try { diff --git a/app/src/main/java/com/dark98/santoku/Santoku.java b/app/src/main/java/com/dark98/santoku/Santoku.java index 1acc11c..bb0ba33 100644 --- a/app/src/main/java/com/dark98/santoku/Santoku.java +++ b/app/src/main/java/com/dark98/santoku/Santoku.java @@ -18,7 +18,6 @@ import java.util.Map; import ru.ytkab0bp.eventbus.EventBus; import com.dark98.santoku.boot.AppBoot; -import com.dark98.santoku.boot.BeamServerDataTask; import com.dark98.santoku.boot.CheckUpdateJsonTask; import com.dark98.santoku.boot.ClearModelCacheTask; import com.dark98.santoku.boot.CloudInitTask; @@ -41,7 +40,6 @@ public class Santoku extends Application { public static TrueTimeImpl TRUE_TIME; public static Slic3rConfigWrapper CONFIG; public static int CONFIG_UID = 0; - public static BeamServerData SERVER_DATA; public static boolean hasUpdateInfo; @SuppressLint("ApplySharedPref") @@ -54,7 +52,6 @@ public class Santoku extends Application { new PrefsTask(), new VibrationUtilsTask(), new TrueTimeTask(), - new BeamServerDataTask(), new PrintConfigWarmupTask(), new CheckUpdateJsonTask(), new ClearModelCacheTask(), diff --git a/app/src/main/java/com/dark98/santoku/SetupActivity.java b/app/src/main/java/com/dark98/santoku/SetupActivity.java index 8b8298c..b2d4df7 100644 --- a/app/src/main/java/com/dark98/santoku/SetupActivity.java +++ b/app/src/main/java/com/dark98/santoku/SetupActivity.java @@ -24,6 +24,7 @@ import android.net.Uri; import android.opengl.GLSurfaceView; import android.os.Build; import android.os.Bundle; +import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.Log; @@ -35,6 +36,8 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.EditText; +import android.widget.CheckBox; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -60,6 +63,7 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; +import ru.ytkab0bp.sapil.APICallback; import org.json.JSONArray; import org.json.JSONException; @@ -94,8 +98,6 @@ import com.dark98.santoku.cloud.CloudController; import com.dark98.santoku.components.BeamAlertDialogBuilder; import com.dark98.santoku.components.CloudManageBottomSheet; import com.dark98.santoku.config.ConfigObject; -import com.dark98.santoku.events.BeamServerDataUpdatedEvent; -import com.dark98.santoku.events.CloudFeaturesUpdatedEvent; import com.dark98.santoku.events.CloudLoginStateUpdatedEvent; import com.dark98.santoku.events.CloudSyncFinishedEvent; import com.dark98.santoku.recycler.BigHeaderItem; @@ -114,14 +116,12 @@ import com.dark98.santoku.theme.ThemesRepo; import com.dark98.santoku.utils.Prefs; import com.dark98.santoku.utils.ViewUtils; import com.dark98.santoku.view.BeamSwitch; -import com.dark98.santoku.view.BoostySubsView; import com.dark98.santoku.view.FadeRecyclerView; import com.dark98.santoku.view.MiniColorView; import com.dark98.santoku.view.TextColorImageSpan; public class SetupActivity extends AppCompatActivity { public final static String EXTRA_ABOUT = "about"; - public final static String EXTRA_BOOSTY_ONLY = "boosty_only"; public final static String EXTRA_CLOUD_PROFILE = "cloud_profile"; public final static String EXTRA_CLOUD_IMPORT_FROM_SETUP = "cloud_import_from_setup"; @@ -129,12 +129,11 @@ public class SetupActivity extends AppCompatActivity { private final static List REPOS_URLS = Arrays.asList( "https://preset-repo-api.prusa3d.com/v1/repos", - "https://raw.githubusercontent.com/utkabobr/SliceBeam/refs/heads/master/.profiledumpsrepo/manifest.json" + "https://raw.githubusercontent.com/Dark98/SliceBeam/refs/heads/master/.profiledumpsrepo/manifest.json" ); private final static int REPOS_INDEX = 1; private final static int PROFILES_INDEX = 2; - private static int BOOSTY_INDEX = 3; private final static int TYPE_PRINTER = 0, TYPE_PRINT_CONFIG = 1, TYPE_FILAMENT = 2; @@ -148,7 +147,6 @@ public class SetupActivity extends AppCompatActivity { private int titleY; private float backgroundProgress; - private float boostyProgress; private SpringAnimation fakeScroller; @@ -166,7 +164,6 @@ public class SetupActivity extends AppCompatActivity { private Map> profilesMap = new HashMap<>(); private boolean isProfilesLoaded; private boolean about; - private boolean boostyOnly; private boolean cloudProfile; private boolean cloudImport; @@ -185,11 +182,10 @@ public class SetupActivity extends AppCompatActivity { Santoku.EVENT_BUS.registerListener(this); about = getIntent().getBooleanExtra(EXTRA_ABOUT, false); - boostyOnly = getIntent().getBooleanExtra(EXTRA_BOOSTY_ONLY, false); cloudProfile = getIntent().getBooleanExtra(EXTRA_CLOUD_PROFILE, false); cloudImport = getIntent().getBooleanExtra(EXTRA_CLOUD_IMPORT_FROM_SETUP, false); - if (!about && !boostyOnly && !cloudProfile) { + if (!about && !cloudProfile) { new BeamAlertDialogBuilder(this) .setTitle(R.string.IntroEarlyAccess) .setMessage(R.string.IntroEarlyAccessMessage) @@ -197,7 +193,7 @@ public class SetupActivity extends AppCompatActivity { .show(); } - if (boostyOnly || cloudProfile) { + if (cloudProfile) { backgroundProgress = 1f; } @@ -205,7 +201,7 @@ public class SetupActivity extends AppCompatActivity { adapter = new SimpleRecyclerAdapter() { @Override public int getItemCount() { - return about || boostyOnly || cloudProfile ? 1 : limitRepoFragmentCount ? REPOS_INDEX + 1 : limitProfileFragmentCount ? PROFILES_INDEX + 1 : super.getItemCount(); + return about || cloudProfile ? 1 : limitRepoFragmentCount ? REPOS_INDEX + 1 : limitProfileFragmentCount ? PROFILES_INDEX + 1 : super.getItemCount(); } }; setItems(); @@ -236,25 +232,12 @@ public class SetupActivity extends AppCompatActivity { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - if (position == 0 && !boostyOnly && !cloudProfile) { + if (position == 0 && !cloudProfile) { backgroundProgress = positionOffset; } else { backgroundProgress = 1f; } - if (boostyOnly) { - boostyProgress = 1f; - } else if (position == BOOSTY_INDEX) { - boostyProgress = 1f - positionOffset; - } else if (position == BOOSTY_INDEX - 1) { - boostyProgress = positionOffset; - } else { - boostyProgress = 0f; - } - if (profilesItem != null && profilesItem.recyclerView != null) { - profilesItem.recyclerView.setOverlayAlpha(1f - boostyProgress); - } - if (position == REPOS_INDEX) { if (!isReposLoaded && !isLoading) { loadRepos(true); @@ -434,17 +417,13 @@ public class SetupActivity extends AppCompatActivity { shader.startUsing(); int topColor = ThemesRepo.getColor(android.R.attr.colorAccent); int bottomColor = ThemesRepo.getColor(android.R.attr.windowBackground); - if (boostyProgress != 0f) { - topColor = ColorUtils.blendARGB(bottomColor, ThemesRepo.getColor(R.attr.boostyColorTop), boostyProgress); - bottomColor = ColorUtils.blendARGB(bottomColor, ThemesRepo.getColor(R.attr.boostyColorBottom), boostyProgress); - } if (cloudProfile) { bottomColor = ColorUtils.blendARGB(bottomColor, topColor, 0.5f); } shader.setUniformColor("top_color", topColor); shader.setUniformColor("bottom_color", bottomColor); - shader.setUniform("progress", backgroundProgress - (cloudProfile ? 1.4f : 0) - (boostyProgress != 0 ? 1.2f : 0)); + shader.setUniform("progress", backgroundProgress - (cloudProfile ? 1.4f : 0)); shader.setUniform("time", time); backgroundModel.render(); shader.stopUsing(); @@ -489,7 +468,7 @@ public class SetupActivity extends AppCompatActivity { title.setPivotY(0); title.setScaleX(sc); title.setScaleY(sc); - int color = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.textColorOnAccent), ThemesRepo.getColor(android.R.attr.colorAccent), cloudProfile ? 0f : backgroundProgress - boostyProgress); + int color = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.textColorOnAccent), ThemesRepo.getColor(android.R.attr.colorAccent), cloudProfile ? 0f : backgroundProgress); title.setTextColor(color); title.setTranslationY(ViewUtils.lerp(titleY, (ViewUtils.dp(52) - title.getHeight() * title.getScaleY()) / 2f, backgroundProgress)); } @@ -501,23 +480,13 @@ public class SetupActivity extends AppCompatActivity { Santoku.EVENT_BUS.unregisterListener(this); } - @EventHandler(runOnMainThread = true) - public void onDataUpdated(BeamServerDataUpdatedEvent e) { - if (!about && !boostyOnly && !cloudProfile) { - boolean wasBoosty = BOOSTY_INDEX != -1; - if (wasBoosty != BeamServerData.isBoostyAvailable()) { - setItems(); - } - } - } - @SuppressLint("NotifyDataSetChanged") @EventHandler(runOnMainThread = true) public void onCloudSyncFinished(CloudSyncFinishedEvent e) { if (cloudProfile && Prefs.getCloudAPIToken() != null && cloudImport) { finish(); } - if (!about && !boostyOnly && !cloudProfile) { + if (!about && !cloudProfile) { if (Prefs.getCloudAPIToken() != null) { limitRepoFragmentCount = false; limitProfileFragmentCount = false; @@ -531,13 +500,8 @@ public class SetupActivity extends AppCompatActivity { public void onCloudAuthStateUpdated(CloudLoginStateUpdatedEvent e) { if (cloudProfile) { cloudItem.bindLoginButton(true); - cloudItem.bindFeatures(); } - } - - @EventHandler(runOnMainThread = true) - public void onCloudFeaturesUpdated(CloudFeaturesUpdatedEvent e) { - if (!about && !boostyOnly && !cloudProfile) { + if (!about && !cloudProfile && reposItem != null) { reposItem.onCloudInfoUpdated(); } } @@ -545,8 +509,6 @@ public class SetupActivity extends AppCompatActivity { private void setItems() { if (cloudProfile){ adapter.setItems(Collections.singletonList(cloudItem = new CloudProfileItem())); - } else if (boostyOnly) { - adapter.setItems(Collections.singletonList(new BoostyItem())); } else if (about) { adapter.setItems(Collections.singletonList(new AboutItem())); } else { @@ -555,13 +517,6 @@ public class SetupActivity extends AppCompatActivity { reposItem = new ReposItem(), profilesItem = new ProfilesItem())); - if (BeamServerData.isBoostyAvailable()) { - BOOSTY_INDEX = items.size(); - items.add(new BoostyItem()); - } else { - BOOSTY_INDEX = -1; - } - items.add(new FinishItem()); adapter.setItems(items); } @@ -685,7 +640,9 @@ public class SetupActivity extends AppCompatActivity { private FrameLayout buttonView; private TextView buttonText; private ProgressBar buttonProgress; - private FadeRecyclerView recyclerView; + private TextView titleView; + private TextView signUpButton; + private boolean signUpInProgress; @Override public View onCreateView(Context ctx) { @@ -693,23 +650,16 @@ public class SetupActivity extends AppCompatActivity { ll.setOrientation(LinearLayout.VERTICAL); ll.setPadding(0, ViewUtils.dp(42), 0, 0); - TextView title = new TextView(ctx); - title.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - title.setText(R.string.SettingsCloudManageDescription); - title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - title.setGravity(Gravity.CENTER); - title.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); - ll.addView(title); + titleView = new TextView(ctx); + titleView.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + titleView.setGravity(Gravity.CENTER); + titleView.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); + ll.addView(titleView); + bindHeader(); - FrameLayout fl = new FrameLayout(ctx); - recyclerView = new FadeRecyclerView(ctx); - recyclerView.setBitmapMode(); - recyclerView.setAdapter(adapter = new SimpleRecyclerAdapter()); - recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER); - fl.addView(recyclerView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); - bindFeatures(); - - ll.addView(fl, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); + View spacer = new View(ctx); + ll.addView(spacer, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); TextView tosButton = new TextView(ctx); SpannableStringBuilder sb = SpannableStringBuilder.valueOf(ctx.getString(R.string.SettingsCloudManageTermsOfService)).append(" "); @@ -724,7 +674,7 @@ public class SetupActivity extends AppCompatActivity { tosButton.setGravity(Gravity.CENTER); tosButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); tosButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); - tosButton.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://beam3d.ru/slicebeam_cloud_tos.html")))); + tosButton.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(BuildConfig.BEAM_BASE_URL_PROD + "/tos")))); ll.addView(tosButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ leftMargin = rightMargin = ViewUtils.dp(16); bottomMargin = ViewUtils.dp(8); @@ -744,27 +694,30 @@ public class SetupActivity extends AppCompatActivity { buttonProgress.setIndeterminateTintList(ColorStateList.valueOf(ThemesRepo.getColor(R.attr.textColorOnAccent))); buttonView.addView(buttonProgress, new FrameLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28), Gravity.CENTER)); - bindLoginButton(false); - ll.addView(buttonView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ leftMargin = rightMargin = ViewUtils.dp(16); + }}); + + signUpButton = new TextView(ctx); + signUpButton.setText(R.string.SettingsCloudManageButtonSignUp); + signUpButton.setTextColor(ThemesRepo.getColor(android.R.attr.colorAccent)); + signUpButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); + signUpButton.setGravity(Gravity.CENTER); + signUpButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + signUpButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); + signUpButton.setOnClickListener(v -> showSignUpDialog(v.getContext())); + ll.addView(signUpButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ + leftMargin = rightMargin = ViewUtils.dp(16); + topMargin = ViewUtils.dp(8); bottomMargin = ViewUtils.dp(16); }}); + bindLoginButton(false); + ll.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return ll; } - private void bindFeatures() { - List items = new ArrayList<>(); - if (CloudController.getUserFeatures() != null) { - for (CloudAPI.SubscriptionLevel lvl : CloudController.getUserFeatures().levels) { - items.add(new CloudSubscriptionLevel(lvl)); - } - } - adapter.setItems(items); - } - private void bindLoginButton(boolean animate) { boolean loggedIn = Prefs.getCloudAPIToken() != null; boolean loading = !loggedIn && CloudController.isLoggingIn(); @@ -819,6 +772,7 @@ public class SetupActivity extends AppCompatActivity { buttonText.setVisibility(loading ? View.GONE : View.VISIBLE); } buttonText.setText(loggedIn ? R.string.SettingsCloudManageButtonManage : R.string.SettingsCloudManageButtonLogIn); + bindHeader(); buttonView.setOnClickListener(v-> { if (loading) { new BeamAlertDialogBuilder(v.getContext()) @@ -833,177 +787,145 @@ public class SetupActivity extends AppCompatActivity { CloudController.beginLogin(); } }); - } - } - private final static class CloudSubscriptionLevel extends SimpleRecyclerItem { - private CloudAPI.SubscriptionLevel level; - - private CloudSubscriptionLevel(CloudAPI.SubscriptionLevel level) { - this.level = level; + if (signUpButton != null) { + boolean showSignUp = !loggedIn && !loading; + signUpButton.setVisibility(showSignUp ? View.VISIBLE : View.GONE); + signUpButton.setEnabled(showSignUp && !signUpInProgress); + signUpButton.setAlpha(signUpButton.isEnabled() ? 1f : 0.6f); + } } - @Override - public LevelHolderView onCreateView(Context ctx) { - return new LevelHolderView(ctx); + private void bindHeader() { + if (titleView == null) return; + CloudAPI.UserInfo info = CloudController.getUserInfo(); + if (Prefs.getCloudAPIToken() != null && info != null && info.displayName != null) { + titleView.setText(titleView.getContext().getString(R.string.SettingsCloudManageLoggedInAs, info.displayName)); + } else { + titleView.setText(R.string.SettingsCloudManageDescription); + } } - @Override - public void onBindView(LevelHolderView view) { - view.bind(this); - } - - public final static class LevelHolderView extends LinearLayout implements IThemeView { - private ImageView icon; - private TextView title; - private TextView price; - - private RecyclerView featuresLayout; - private SimpleRecyclerAdapter featuresAdapter; - - public LevelHolderView(@NonNull Context context) { - super(context); - - setOrientation(VERTICAL); - setPadding(0, ViewUtils.dp(16), 0, ViewUtils.dp(8)); - - LinearLayout inner = new LinearLayout(context); - inner.setOrientation(HORIZONTAL); - inner.setGravity(Gravity.CENTER_VERTICAL); - inner.setPadding(ViewUtils.dp(28), 0, ViewUtils.dp(28), 0); - addView(inner, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - bottomMargin = ViewUtils.dp(8); - }}); - - icon = new ImageView(context); - inner.addView(icon, new LayoutParams(ViewUtils.dp(26), ViewUtils.dp(26))); - - title = new TextView(context); - title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - inner.addView(title, new LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) {{ - leftMargin = ViewUtils.dp(12); - }}); - - price = new TextView(context); - price.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - price.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - inner.addView(price); - - featuresLayout = new RecyclerView(context) { - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - return false; - } - - @Override - protected boolean dispatchHoverEvent(MotionEvent event) { - return false; - } - }; - featuresLayout.setLayoutManager(new LinearLayoutManager(context)); - featuresLayout.setAdapter(featuresAdapter = new SimpleRecyclerAdapter()); - addView(featuresLayout, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - topMargin = ViewUtils.dp(3); - leftMargin = rightMargin = ViewUtils.dp(16); - bottomMargin = ViewUtils.dp(8); - }}); - - setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - leftMargin = rightMargin = ViewUtils.dp(12); - topMargin = ViewUtils.dp(12); - }}); - onApplyTheme(); + private void showSignUpDialog(Context ctx) { + if (signUpInProgress) { + return; } - public void bind(CloudSubscriptionLevel item) { - CloudAPI.SubscriptionLevel lvl = item.level; - title.setText(lvl.title); - price.setText(lvl.price); - if (lvl.level <= 0) { - icon.setImageResource(R.drawable.zero_ruble_outline_28); - price.setText(R.string.SettingsCloudManageFree); - } else if (lvl.level == 1) { - icon.setImageResource(R.drawable.stars_outline_28); + LinearLayout ll = new LinearLayout(ctx); + ll.setOrientation(LinearLayout.VERTICAL); + ll.setPadding(ViewUtils.dp(16), ViewUtils.dp(8), ViewUtils.dp(16), 0); + + TextView emailLabel = new TextView(ctx); + emailLabel.setText(R.string.SettingsCloudManageSignUpEmail); + emailLabel.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + emailLabel.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(emailLabel, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + EditText emailInput = new EditText(ctx); + emailInput.setHint(R.string.SettingsCloudManageSignUpEmail); + emailInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + emailInput.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); + emailInput.setHintTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(emailInput, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + TextView displayNameLabel = new TextView(ctx); + displayNameLabel.setText(R.string.SettingsCloudManageSignUpDisplayName); + displayNameLabel.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + displayNameLabel.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(displayNameLabel, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(12); + }}); + + EditText displayNameInput = new EditText(ctx); + displayNameInput.setHint(R.string.SettingsCloudManageSignUpDisplayName); + displayNameInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PERSON_NAME); + displayNameInput.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); + displayNameInput.setHintTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(displayNameInput, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(8); + }}); + + TextView passwordLabel = new TextView(ctx); + passwordLabel.setText(R.string.SettingsCloudManageSignUpPassword); + passwordLabel.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + passwordLabel.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(passwordLabel, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(12); + }}); + + EditText passwordInput = new EditText(ctx); + passwordInput.setHint(R.string.SettingsCloudManageSignUpPassword); + passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); + passwordInput.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); + passwordInput.setHintTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + ll.addView(passwordInput, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(8); + }}); + + CheckBox showPassword = new CheckBox(ctx); + showPassword.setText(R.string.SettingsCloudManageSignUpShowPassword); + showPassword.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); + showPassword.setOnCheckedChangeListener((buttonView, isChecked) -> { + int selection = passwordInput.getSelectionEnd(); + if (isChecked) { + passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD); } else { - icon.setImageResource(R.drawable.cloud_plus_outline_28); + passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); } + passwordInput.setSelection(Math.max(selection, 0)); + }); + ll.addView(showPassword, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(4); + }}); - List items = new ArrayList<>(); - CloudAPI.UserFeatures features = CloudController.getUserFeatures(); - CloudAPI.UserInfo info = CloudController.getUserInfo(); - Context ctx = getContext(); - if (!BuildConfig.IS_GOOGLE_PLAY && features.earlyAccessLevel != -1 && lvl.level >= features.earlyAccessLevel) { - items.add(new PreferenceItem() - .setForceDark(true) - .setPaddings(ViewUtils.dp(8)) - .setIcon(R.drawable.clock_circle_dashed_outline_24) - .setTitle(ctx.getString(R.string.SettingsCloudManageFeatureEarlyAccess)) - .setSubtitle(ctx.getString(R.string.SettingsCloudManageFeatureEarlyAccessDescription))); - } - if (features.syncRequiredLevel != -1 && lvl.level >= features.syncRequiredLevel) { - items.add(new PreferenceItem() - .setForceDark(true) - .setPaddings(ViewUtils.dp(8)) - .setIcon(R.drawable.sync_outline_28) - .setTitle(ctx.getString(R.string.SettingsCloudManageFeatureCloudSync)) - .setSubtitle(ctx.getString(R.string.SettingsCloudManageFeatureCloudSyncDescription))); - } - if (features.aiGeneratorRequiredLevel != -1 && lvl.level >= features.aiGeneratorRequiredLevel) { - items.add(new PreferenceItem() - .setForceDark(true) - .setPaddings(ViewUtils.dp(8)) - .setIcon(R.drawable.brain_outline_28) - .setTitle(ctx.getString(R.string.SettingsCloudManageFeatureAIGenerator)) - .setSubtitle(ctx.getString(R.string.SettingsCloudManageFeatureAIGeneratorDescription, features.aiGeneratorModelsPerMonth))); - } - if (lvl.level > 0) { - items.add(new PreferenceItem() - .setForceDark(true) - .setPaddings(ViewUtils.dp(8)) - .setIcon(R.drawable.box_heart_outline_28) - .setTitle(ctx.getString(R.string.SettingsCloudManageFeatureFreeForAll)) - .setSubtitle(ctx.getString(R.string.SettingsCloudManageFeatureFreeForAllDescription))); - } - featuresAdapter.setItems(items); - featuresLayout.setVisibility(items.isEmpty() ? View.GONE : View.VISIBLE); + TextView dialogTitle = new TextView(ctx); + dialogTitle.setText(R.string.SettingsCloudManageButtonSignUp); + dialogTitle.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); + dialogTitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 28); + dialogTitle.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); + dialogTitle.setGravity(Gravity.CENTER); + dialogTitle.setPadding(0, ViewUtils.dp(4), 0, ViewUtils.dp(8)); + ll.addView(dialogTitle, 0, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - boolean subscribed = lvl.level > 0 && info != null && lvl.level == info.currentLevel; - boolean allowSubscribe = lvl.level > 0 && (info == null || lvl.level > info.currentLevel); - if (subscribed) { - price.setText(R.string.SettingsCloudManageSubscribed); - } - price.setVisibility(allowSubscribe || subscribed ? View.VISIBLE : View.GONE); - setOnClickListener(v -> { - if (subscribed) { - v.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(lvl.manageUrl))); - } else { - new BeamAlertDialogBuilder(getContext()) - .setTitle(lvl.title) - .setMessage(R.string.SettingsCloudManageLevelRedirectMessage) - .setPositiveButton(android.R.string.ok, (dialog, which) -> v.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(lvl.subscribeOrUpgradeUrl)))) - .setNegativeButton(R.string.SettingsCloudManageLevelRedirectAlreadySubscribed, (dialog, which) -> v.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(features.alreadySubscribedInfoUrl)))) - .show(); - } - }); - setClickable(allowSubscribe || subscribed); - onApplyTheme(); - } + new BeamAlertDialogBuilder(ctx) + .setView(ll) + .setNegativeButton(android.R.string.cancel, null) + .setPositiveButton(R.string.SettingsCloudManageButtonSignUp, (dialog, which) -> { + String email = emailInput.getText().toString().trim(); + String displayName = displayNameInput.getText().toString().trim(); + String password = passwordInput.getText().toString(); + if (TextUtils.isEmpty(email) || TextUtils.isEmpty(displayName) || TextUtils.isEmpty(password)) { + Toast.makeText(ctx, R.string.SettingsCloudManageSignUpMissingFields, Toast.LENGTH_SHORT).show(); + return; + } + signUpInProgress = true; + bindLoginButton(true); + CloudAPI.INSTANCE.signup(email, password, displayName, new APICallback() { + @Override + public void onResponse(CloudAPI.AuthToken response) { + Prefs.setCloudAPIToken(response.bearer); + signUpInProgress = false; + CloudController.init(); + Santoku.EVENT_BUS.fireEvent(new CloudLoginStateUpdatedEvent()); + } - @Override - public void onApplyTheme() { - int accent = ThemesRepo.getColor(android.R.attr.colorAccent); - if (ColorUtils.calculateLuminance(accent) >= 0.6f) { - accent = ColorUtils.blendARGB(accent, Color.BLACK, 0.075f); - } - boolean tooLight = ColorUtils.calculateLuminance(accent) >= 0.6f; - title.setTextColor(0xffffffff); - price.setTextColor(0xffffffff); - icon.setImageTintList(ColorStateList.valueOf(0xffffffff)); - featuresLayout.setBackground(ViewUtils.createRipple(0, tooLight ? 0x33ffffff : 0x21ffffff, 24)); - setBackground(ViewUtils.createRipple(0x21000000, ColorUtils.blendARGB(0xffffffff, accent, tooLight ? 0.9f : 0.75f), 32)); - } + @Override + public void onException(Exception e) { + signUpInProgress = false; + ViewUtils.postOnMainThread(() -> { + new BeamAlertDialogBuilder(ctx) + .setTitle(R.string.SettingsCloudManageSignUpFailed) + .setMessage(e.toString()) + .setPositiveButton(android.R.string.ok, null) + .show(); + bindLoginButton(true); + }); + } + }); + }) + .show(); } + } private final class AboutItem extends SimpleRecyclerItem { @@ -1235,9 +1157,9 @@ public class SetupActivity extends AppCompatActivity { progressBar.setIndeterminateTintList(ColorStateList.valueOf(ThemesRepo.getColor(android.R.attr.colorAccent))); cloudImportView.setTextColor(ThemesRepo.getColor(android.R.attr.colorAccent)); cloudImportView.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); - cloudImportView.setVisibility(BeamServerData.isCloudAvailable() ? View.VISIBLE : View.GONE); + cloudImportView.setVisibility(Prefs.getCloudAPIToken() != null ? View.VISIBLE : View.GONE); cloudOrView.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); - cloudOrView.setVisibility(BeamServerData.isCloudAvailable() ? View.VISIBLE : View.GONE); + cloudOrView.setVisibility(Prefs.getCloudAPIToken() != null ? View.VISIBLE : View.GONE); customProfileView.setTextColor(ThemesRepo.getColor(android.R.attr.colorAccent)); customProfileView.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); buttonView.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), ThemesRepo.getColor(android.R.attr.colorAccent), 16)); @@ -1264,8 +1186,8 @@ public class SetupActivity extends AppCompatActivity { public void onCloudInfoUpdated() { if (cloudImportView != null) { - cloudImportView.setVisibility(BeamServerData.isCloudAvailable() ? View.VISIBLE : View.GONE); - cloudOrView.setVisibility(BeamServerData.isCloudAvailable() ? View.VISIBLE : View.GONE); + cloudImportView.setVisibility(Prefs.getCloudAPIToken() != null ? View.VISIBLE : View.GONE); + cloudOrView.setVisibility(Prefs.getCloudAPIToken() != null ? View.VISIBLE : View.GONE); } } @@ -1425,80 +1347,6 @@ public class SetupActivity extends AppCompatActivity { } } - private final class BoostyItem extends SimpleRecyclerItem { - - @Override - public View onCreateView(Context ctx) { - LinearLayout ll = new LinearLayout(ctx); - ll.setOrientation(LinearLayout.VERTICAL); - ll.setPadding(0, ViewUtils.dp(42), 0, 0); - - TextView title = new TextView(ctx); - title.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - title.setText(R.string.IntroBoostyTitle); - title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - title.setGravity(Gravity.CENTER); - title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - title.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); - ll.addView(title); - - BoostySubsView subsView = new BoostySubsView(ctx); - if (Santoku.SERVER_DATA != null) { - List list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers); - Collections.shuffle(list); - subsView.setStrings(list); - } - ll.addView(subsView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f) {{ - bottomMargin = ViewUtils.dp(64); - }}); - - TextView subscribeButton = new TextView(ctx); - SpannableStringBuilder sb = SpannableStringBuilder.valueOf(ctx.getString(R.string.IntroBoostySupport)).append(" "); - Drawable dr = ContextCompat.getDrawable(ctx, R.drawable.external_link_outline_24); - int size = ViewUtils.dp(16); - dr.setBounds(0, 0, size, size); - sb.append("d", new TextColorImageSpan(dr, ViewUtils.dp(2f)), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); - subscribeButton.setText(sb); - subscribeButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - subscribeButton.setTextColor(Color.WHITE); - subscribeButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - subscribeButton.setGravity(Gravity.CENTER); - subscribeButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); - subscribeButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); - subscribeButton.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://boosty.to/ytkab0bp")))); - ll.addView(subscribeButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ - leftMargin = rightMargin = ViewUtils.dp(16); - bottomMargin = ViewUtils.dp(8); - }}); - - TextView buttonView = new TextView(ctx); - if (boostyOnly) { - buttonView.setText(android.R.string.ok); - } else { - buttonView.setText(R.string.IntroNext); - } - buttonView.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - buttonView.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - buttonView.setGravity(Gravity.CENTER); - buttonView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - buttonView.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), ThemesRepo.getColor(R.attr.boostyColorTop), 16)); - buttonView.setOnClickListener(v-> { - if (boostyOnly) { - finish(); - return; - } - scrollToNext(); - }); - ll.addView(buttonView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52)) {{ - leftMargin = rightMargin = ViewUtils.dp(16); - bottomMargin = ViewUtils.dp(16); - }}); - - ll.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - return ll; - } - } - private final class FinishItem extends SimpleRecyclerItem { private TextView buttonView; diff --git a/app/src/main/java/com/dark98/santoku/boot/BeamServerDataTask.java b/app/src/main/java/com/dark98/santoku/boot/BeamServerDataTask.java deleted file mode 100644 index a4008d9..0000000 --- a/app/src/main/java/com/dark98/santoku/boot/BeamServerDataTask.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.dark98.santoku.boot; - -import org.json.JSONException; -import org.json.JSONObject; - -import com.dark98.santoku.BeamServerData; -import com.dark98.santoku.Santoku; -import com.dark98.santoku.utils.Prefs; -import com.dark98.santoku.utils.ViewUtils; - -public class BeamServerDataTask extends BootTask { - public BeamServerDataTask() { - super(() -> { - try { - Santoku.SERVER_DATA = new BeamServerData(new JSONObject(Prefs.getBeamServerData())); - } catch (JSONException e) { - throw new RuntimeException(e); - } - if (System.currentTimeMillis() - Prefs.getLastCheckedInfo() >= 86400000L) { - ViewUtils.postOnMainThread(BeamServerData::load); - } - }); - onWorker(); - } -} diff --git a/app/src/main/java/com/dark98/santoku/cloud/CloudAPI.java b/app/src/main/java/com/dark98/santoku/cloud/CloudAPI.java index 26494bc..cda45fd 100644 --- a/app/src/main/java/com/dark98/santoku/cloud/CloudAPI.java +++ b/app/src/main/java/com/dark98/santoku/cloud/CloudAPI.java @@ -2,12 +2,7 @@ package com.dark98.santoku.cloud; import androidx.annotation.Nullable; -import com.google.gson.Gson; - -import java.io.InputStream; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import ru.ytkab0bp.sapil.APICallback; @@ -27,7 +22,7 @@ public interface CloudAPI extends APIRunner { @Override public String getBaseURL() { - return "https://api.beam3d.ru/v1/"; + return BuildConfig.CLOUD_BASE_URL_PROD; } @Override @@ -72,10 +67,16 @@ public interface CloudAPI extends APIRunner { void userGetInfo(APICallback callback); /** - * Gets user features + * Creates a new account (email/password) */ - @Method("user/getFeatures") - void userGetFeatures(APICallback callback); + @Method(requestType = RequestType.POST, value = "signup") + void signup(@Arg("email") String email, @Arg("password") String password, @Arg("displayName") String displayName, APICallback callback); + + /** + * Login with email/password + */ + @Method(requestType = RequestType.POST, value = "login") + void login(@Arg("email") String email, @Arg("password") String password, APICallback callback); /** * Fetches sync state @@ -103,24 +104,6 @@ public interface CloudAPI extends APIRunner { @Method("sync/get") void syncGet(APICallback callback); - /** - * Generates 3D model from image - *

- * @param image Base64 encoded image - *

- * Requires authorization - */ - @Method(requestType = RequestType.POST, value = "models/generate") - void modelsGenerate(@Arg("") String image, @Header("Content-Type") String type, APICallback callback); - - /** - * Gets remaining model generations count - *

- * Requires authorization - */ - @Method("models/getRemainingCount") - void modelsGetRemainingCount(APICallback callback); - /** * Destroys token *

@@ -158,66 +141,13 @@ public interface CloudAPI extends APIRunner { public String bearer; } - final class UserFeatures { + final class AuthToken { /** - * Which level is required for early access + * Bearer token */ - public int earlyAccessLevel; - - /** - * Which level is required for data sync - */ - public int syncRequiredLevel; - - /** - * Which level is required for AI model generator - */ - public int aiGeneratorRequiredLevel; - - /** - * Models per month max - */ - public int aiGeneratorModelsPerMonth; - - /** - * Url at which user should be redirected for info about how to restore a subscription - */ - public String alreadySubscribedInfoUrl; - - /** - * List of subscription levels - */ - public List levels = new ArrayList<>(); + public String bearer; } - final class SubscriptionLevel { - /** - * Int representation - */ - public int level; - - /** - * Title of this level - */ - public String title; - - /** - * Price of this level - */ - public String price; - - /** - * Url at which user should be redirected for purchase - */ - public String subscribeOrUpgradeUrl; - - /** - * Url at which user should be redirected for managing the subscription - */ - public String manageUrl; - } - - final class UserInfo { /** * User's id @@ -235,10 +165,6 @@ public interface CloudAPI extends APIRunner { @Nullable public String avatarUrl; - /** - * Current subscription level - */ - public int currentLevel; } @@ -259,15 +185,4 @@ public interface CloudAPI extends APIRunner { public long maxSize; } - final class ModelsRemainingCount { - /** - * Used generations - */ - public int used; - - /** - * Max available generations - */ - public int max; - } } diff --git a/app/src/main/java/com/dark98/santoku/cloud/CloudController.java b/app/src/main/java/com/dark98/santoku/cloud/CloudController.java index f62f2ca..a7488d3 100644 --- a/app/src/main/java/com/dark98/santoku/cloud/CloudController.java +++ b/app/src/main/java/com/dark98/santoku/cloud/CloudController.java @@ -21,9 +21,7 @@ import ru.ytkab0bp.sapil.APIRequestHandle; import com.dark98.santoku.R; import com.dark98.santoku.Santoku; import com.dark98.santoku.components.BeamAlertDialogBuilder; -import com.dark98.santoku.events.CloudFeaturesUpdatedEvent; import com.dark98.santoku.events.CloudLoginStateUpdatedEvent; -import com.dark98.santoku.events.CloudModelsRemainingCountUpdatedEvent; import com.dark98.santoku.events.CloudSyncFinishedEvent; import com.dark98.santoku.events.CloudUserInfoUpdatedEvent; import com.dark98.santoku.events.NeedDismissSnackbarEvent; @@ -35,19 +33,13 @@ import com.dark98.santoku.utils.ViewUtils; import com.dark98.santoku.view.SnackbarsLayout; public class CloudController { - public final static String USER_INFO_AI_GEN_TAG = "ai_gen_user_info"; public final static String CLOUD_SYNC_TAG = "cloud_sync"; private final static String TAG = "cloud"; private final static long MIN_SYNC_DELTA = 5 * 60 * 1000L; // Once in 5 minutes - private final static long MIN_SYNC_FEATURES_DELTA = 12 * 60 * 60 * 1000L; // Once in 12 hours - private static boolean isSyncInProgress; private static CloudAPI.UserInfo userInfo; - private static CloudAPI.UserFeatures userFeatures; - private static int modelsUsed; - private static int modelsMaxGenerations; private static boolean isLoggingIn; private static APIRequestHandle beginLoginHandle; private static String loginSessionId; @@ -86,31 +78,21 @@ public class CloudController { private static Gson gson = new Gson(); public static void initCached() { - if (Prefs.getCloudCachedUserFeatures() != null) { - userFeatures = gson.fromJson(Prefs.getCloudCachedUserFeatures(), CloudAPI.UserFeatures.class); - } if (Prefs.getCloudAPIToken() != null) { if (Prefs.getCloudCachedUserInfo() != null) { userInfo = gson.fromJson(Prefs.getCloudCachedUserInfo(), CloudAPI.UserInfo.class); - modelsUsed = Prefs.getCloudCachedUsedModels(); - modelsMaxGenerations = Prefs.getCloudCachedMaxModels(); } } } public static void init() { - long now = Santoku.TRUE_TIME.now().getTime(); - boolean needSyncInfo = userFeatures == null || now - Prefs.getCloudLastFeaturesSync() > MIN_SYNC_FEATURES_DELTA; - if (needSyncInfo) { - checkUserFeatures(); - } - if (Prefs.getCloudAPIToken() != null) { - if (needSyncInfo || userInfo == null) { + long now = Santoku.TRUE_TIME.now().getTime(); + if (userInfo == null) { loadUserInfo(); } - if (!needSyncInfo && userInfo != null && isSyncAvailable() && Prefs.isCloudProfileSyncEnabled()) { + if (userInfo != null && isSyncAvailable() && Prefs.isCloudProfileSyncEnabled()) { if (now - Prefs.getCloudLastSync() > MIN_SYNC_DELTA) { syncData(); } @@ -137,7 +119,6 @@ public class CloudController { } else { Prefs.setCloudCachedUserInfo(gson.toJson(userInfo)); - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(USER_INFO_AI_GEN_TAG)); Santoku.EVENT_BUS.fireEvent(new CloudUserInfoUpdatedEvent()); if (isLoggingIn) { @@ -148,9 +129,7 @@ public class CloudController { if (isSyncAvailable() && Prefs.isCloudProfileSyncEnabled()) { syncData(); } - checkGeneratorRemaining(); } - Prefs.setCloudLastFeaturesSync(Santoku.TRUE_TIME.now().getTime()); } @Override @@ -205,77 +184,23 @@ public class CloudController { } public static void logout() { + CloudAPI.INSTANCE.logout(response -> {}); Prefs.setCloudAPIToken(null); userInfo = null; Santoku.EVENT_BUS.fireEvent(new CloudLoginStateUpdatedEvent()); Santoku.EVENT_BUS.fireEvent(new CloudUserInfoUpdatedEvent()); - CloudAPI.INSTANCE.logout(response -> {}); - } - - public static void checkGeneratorRemaining() { - CloudAPI.INSTANCE.modelsGetRemainingCount(new APICallback() { - @Override - public void onResponse(CloudAPI.ModelsRemainingCount response) { - modelsUsed = response.used; - modelsMaxGenerations = response.max; - Prefs.setCloudCachedUsedMaxModels(modelsUsed, modelsMaxGenerations); - Santoku.EVENT_BUS.fireEvent(new CloudModelsRemainingCountUpdatedEvent()); - } - - @Override - public void onException(Exception e) { - Log.e(TAG, "Failed to check remaining models", e); - ViewUtils.postOnMainThread(CloudController::checkGeneratorRemaining, 15000); - } - }); - } - - public static void checkUserFeatures() { - CloudAPI.INSTANCE.userGetFeatures(new APICallback() { - @Override - public void onResponse(CloudAPI.UserFeatures response) { - userFeatures = response; - Prefs.setCloudCachedUserFeatures(gson.toJson(userFeatures)); - if (Prefs.getCloudAPIToken() == null) { - Prefs.setCloudLastFeaturesSync(Santoku.TRUE_TIME.now().getTime()); - } - Santoku.EVENT_BUS.fireEvent(new CloudFeaturesUpdatedEvent()); - } - - @Override - public void onException(Exception e) { - Log.e(TAG, "Failed to get user features", e); - ViewUtils.postOnMainThread(CloudController::checkUserFeatures, 15000); - } - }); } public static CloudAPI.UserInfo getUserInfo() { return userInfo; } - public static CloudAPI.UserFeatures getUserFeatures() { - return userFeatures; - } - public static boolean hasAccountFeatures() { - return userFeatures != null && userFeatures.levels != null && !userFeatures.levels.isEmpty(); + return true; } public static boolean isSyncAvailable() { - return Prefs.getCloudAPIToken() != null && userInfo != null && userFeatures != null && userInfo.currentLevel >= userFeatures.syncRequiredLevel; - } - - public static boolean needShowAIGenerator() { - return userFeatures != null && userFeatures.aiGeneratorRequiredLevel >= 0; - } - - public static int getGeneratedModels() { - return modelsUsed; - } - - public static int getMaxGeneratedModels() { - return modelsMaxGenerations; + return Prefs.getCloudAPIToken() != null && userInfo != null; } private static void downloadData(long lastModified) { diff --git a/app/src/main/java/com/dark98/santoku/components/ChangeLogBottomSheet.java b/app/src/main/java/com/dark98/santoku/components/ChangeLogBottomSheet.java index a8f2d00..8d85ddb 100644 --- a/app/src/main/java/com/dark98/santoku/components/ChangeLogBottomSheet.java +++ b/app/src/main/java/com/dark98/santoku/components/ChangeLogBottomSheet.java @@ -1,9 +1,7 @@ package com.dark98.santoku.components; import android.content.Context; -import android.content.Intent; import android.graphics.drawable.GradientDrawable; -import android.net.Uri; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; @@ -13,13 +11,9 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.ScrollView; -import android.widget.Scroller; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.core.graphics.ColorUtils; -import androidx.viewpager.widget.PagerAdapter; -import androidx.viewpager.widget.ViewPager; import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetDialog; @@ -28,26 +22,17 @@ import org.json.JSONObject; import java.io.ByteArrayOutputStream; import java.io.InputStream; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Locale; -import ru.ytkab0bp.eventbus.EventHandler; -import com.dark98.santoku.BeamServerData; import com.dark98.santoku.R; import com.dark98.santoku.Santoku; -import com.dark98.santoku.events.BeamServerDataUpdatedEvent; import com.dark98.santoku.theme.ThemesRepo; import com.dark98.santoku.utils.ViewUtils; import com.dark98.santoku.view.BeamButton; -import com.dark98.santoku.view.BoostySubsView; public class ChangeLogBottomSheet extends BottomSheetDialog { - private BoostySubsView subsView; private ScrollView scrollView; - private ViewPager pager; public ChangeLogBottomSheet(@NonNull Context context) { super(context); @@ -77,18 +62,6 @@ public class ChangeLogBottomSheet extends BottomSheetDialog { }}); fl.addView(titleA); - TextView titleB = new TextView(context); - titleB.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - titleB.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - titleB.setText(R.string.ChangelogBoosty); - titleB.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - titleB.setGravity(Gravity.CENTER); - titleB.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - leftMargin = rightMargin = ViewUtils.dp(21); - }}); - titleB.setAlpha(0f); - fl.addView(titleB); - ll.addView(fl); scrollView = new ScrollView(context); @@ -120,112 +93,11 @@ public class ChangeLogBottomSheet extends BottomSheetDialog { scrollView.addView(text); DisplayMetrics dm = context.getResources().getDisplayMetrics(); + ll.addView(scrollView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) (dm.heightPixels * 0.45f))); - pager = new ViewPager(context) {{ - try { - Field scroller = ViewPager.class.getDeclaredField("mScroller"); - scroller.setAccessible(true); - - Scroller mScroller = new Scroller(getContext(), ViewUtils.CUBIC_INTERPOLATOR::getInterpolation); - scroller.set(this, mScroller); - } catch (Exception ignored) {} - }}; - pager.setAdapter(new PagerAdapter() { - @Override - public int getCount() { - return BeamServerData.isBoostyAvailable() ? 2 : 1; - } - - @NonNull - @Override - public Object instantiateItem(@NonNull ViewGroup container, int position) { - View v; - if (position == 0) { - v = scrollView; - } else { - LinearLayout ll = new LinearLayout(context); - ll.setOrientation(LinearLayout.VERTICAL); - - TextView subtitle = new TextView(context); - subtitle.setTextColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - subtitle.setText(R.string.ChangelogBoostyDescription); - subtitle.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - subtitle.setGravity(Gravity.CENTER); - subtitle.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - subtitle.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); - ll.addView(subtitle); - - subsView = new BoostySubsView(context); - if (Santoku.SERVER_DATA != null) { - List list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers); - Collections.shuffle(list); - subsView.setStrings(list); - } - ll.addView(subsView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); - - TextView subscribeButton = new TextView(context); - subscribeButton.setText(R.string.IntroBoostySupport); - subscribeButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - subscribeButton.setTextColor(ThemesRepo.getColor(R.attr.boostyColorTop)); - subscribeButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - subscribeButton.setGravity(Gravity.CENTER); - subscribeButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); - subscribeButton.setOnClickListener(v2 -> context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://boosty.to/ytkab0bp")))); - ll.addView(subscribeButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - - v = ll; - } - - container.addView(v); - return v; - } - - @Override - public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { - container.removeView((View) object); - } - - @Override - public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { - return view == object; - } - }); BeamButton btn = new BeamButton(context); - pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { - @Override - public void onPageSelected(int position) { - super.onPageSelected(position); - if (position == pager.getAdapter().getCount() - 1) { - btn.setText(R.string.ChangelogOK); - } else { - btn.setText(R.string.ChangelogNext); - } - } - - private int[] colors = new int[2]; - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - float pr = position == 0 ? positionOffset : 1f; - colors[0] = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.dialogBackground), ThemesRepo.getColor(R.attr.boostyColorTop), pr); - colors[1] = ColorUtils.blendARGB(ThemesRepo.getColor(R.attr.dialogBackground), ThemesRepo.getColor(R.attr.boostyColorBottom), pr); - gd.setColors(colors); - titleA.setAlpha(1f - pr); - titleA.setTranslationX(-titleA.getWidth() * 0.25f * pr); - titleB.setAlpha(pr); - titleB.setTranslationX(titleB.getWidth() * 0.25f * (1f - pr)); - btn.setColor(ColorUtils.blendARGB(ThemesRepo.getColor(android.R.attr.colorAccent), ThemesRepo.getColor(R.attr.boostyColorTop), pr)); - } - }); - ll.addView(pager, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, (int) (dm.heightPixels * 0.45f))); - - btn.setText(R.string.ChangelogNext); - btn.setOnClickListener(v -> { - if (pager.getCurrentItem() != pager.getAdapter().getCount() - 1) { - pager.setCurrentItem(pager.getCurrentItem() + 1); - } else { - dismiss(); - } - }); + btn.setText(R.string.ChangelogOK); + btn.setOnClickListener(v -> dismiss()); ll.addView(btn, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(48)) {{ leftMargin = topMargin = rightMargin = bottomMargin = ViewUtils.dp(12); }}); @@ -233,18 +105,6 @@ public class ChangeLogBottomSheet extends BottomSheetDialog { ll.setFitsSystemWindows(true); setContentView(ll); - Santoku.EVENT_BUS.registerListener(this); - setOnDismissListener(dialog -> Santoku.EVENT_BUS.unregisterListener(this)); - } - - @EventHandler(runOnMainThread = true) - public void onDataUpdated(BeamServerDataUpdatedEvent e) { - if (Santoku.SERVER_DATA != null) { - List list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers); - Collections.shuffle(list); - subsView.setStrings(list); - } - pager.getAdapter().notifyDataSetChanged(); } @Override diff --git a/app/src/main/java/com/dark98/santoku/components/CloudManageBottomSheet.java b/app/src/main/java/com/dark98/santoku/components/CloudManageBottomSheet.java index 3918b67..395a328 100644 --- a/app/src/main/java/com/dark98/santoku/components/CloudManageBottomSheet.java +++ b/app/src/main/java/com/dark98/santoku/components/CloudManageBottomSheet.java @@ -10,7 +10,6 @@ import android.util.TypedValue; import android.view.Gravity; import android.view.ViewGroup; import android.widget.LinearLayout; -import android.widget.Space; import android.widget.TextView; import androidx.annotation.NonNull; @@ -26,7 +25,7 @@ import java.util.List; import com.dark98.santoku.R; import com.dark98.santoku.Santoku; -import com.dark98.santoku.cloud.CloudAPI; +import com.dark98.santoku.BuildConfig; import com.dark98.santoku.cloud.CloudController; import com.dark98.santoku.events.NeedDismissSnackbarEvent; import com.dark98.santoku.recycler.PreferenceSwitchItem; @@ -65,77 +64,56 @@ public class CloudManageBottomSheet extends BottomSheetDialog { }}); ll.addView(title); - TextView description = new TextView(context); - description.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - description.setText(context.getString(R.string.SettingsCloudManageLoggedInAs, CloudController.getUserInfo().displayName)); - description.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); - description.setGravity(Gravity.CENTER); - description.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - leftMargin = rightMargin = ViewUtils.dp(21); - topMargin = ViewUtils.dp(8); + List items = new ArrayList<>(); + items.add(new PreferenceSwitchItem() + .setIcon(R.drawable.sync_outline_28) + .setTitle(context.getString(R.string.SettingsCloudManageFeatureCloudSync)) + .setValueProvider(Prefs::isCloudProfileSyncEnabled) + .setChangeListener((buttonView, isChecked) -> { + Prefs.setCloudProfileSyncEnabled(isChecked); + if (isChecked) { + CloudController.notifyDataChanged(); + } else { + Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(CloudController.CLOUD_SYNC_TAG)); + } + })); + RecyclerView recyclerView = new RecyclerView(context); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + recyclerView.setBackground(ViewUtils.createRipple(0, ColorUtils.setAlphaComponent(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 0x10), 16)); + SimpleRecyclerAdapter adapter = new SimpleRecyclerAdapter(); + adapter.setItems(items); + recyclerView.setAdapter(adapter); + ll.addView(recyclerView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ + topMargin = ViewUtils.dp(16); + leftMargin = rightMargin = ViewUtils.dp(16); }}); - ll.addView(description); - int currentLevel = CloudController.getUserInfo().currentLevel; - CloudAPI.SubscriptionLevel lvl = null; - CloudAPI.UserFeatures features = CloudController.getUserFeatures(); - for (CloudAPI.SubscriptionLevel level : features.levels) { - if (level.level != -1 && level.level <= currentLevel && (lvl == null || level.level > lvl.level)) { - lvl = level; + TextView manageButton = new TextView(context); + SpannableStringBuilder sb = SpannableStringBuilder.valueOf(context.getString(R.string.SettingsCloudManageSubscription)).append(" "); + Drawable dr = ContextCompat.getDrawable(context, R.drawable.external_link_outline_24); + int size = ViewUtils.dp(16); + dr.setBounds(0, 0, size, size); + sb.append("d", new TextColorImageSpan(dr, ViewUtils.dp(2f)), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + manageButton.setText(sb); + manageButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + manageButton.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); + manageButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); + manageButton.setGravity(Gravity.CENTER); + manageButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); + manageButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); + manageButton.setOnClickListener(v -> { + String url = BuildConfig.BEAM_BASE_URL_PROD + "/account"; + String token = Prefs.getCloudAPIToken(); + if (token != null) { + Uri uri = Uri.parse(url); + url = uri.buildUpon().appendQueryParameter("token", token).build().toString(); } - } - - if (lvl != null) { - List items = new ArrayList<>(); - if (currentLevel >= features.syncRequiredLevel) { - items.add(new PreferenceSwitchItem() - .setIcon(R.drawable.sync_outline_28) - .setTitle(context.getString(R.string.SettingsCloudManageFeatureCloudSync)) - .setValueProvider(Prefs::isCloudProfileSyncEnabled) - .setChangeListener((buttonView, isChecked) -> { - Prefs.setCloudProfileSyncEnabled(isChecked); - if (isChecked) { - CloudController.notifyDataChanged(); - } else { - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(CloudController.CLOUD_SYNC_TAG)); - } - })); - } - if (!items.isEmpty()) { - RecyclerView recyclerView = new RecyclerView(context); - recyclerView.setLayoutManager(new LinearLayoutManager(context)); - recyclerView.setBackground(ViewUtils.createRipple(0, ColorUtils.setAlphaComponent(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 0x10), 16)); - SimpleRecyclerAdapter adapter = new SimpleRecyclerAdapter(); - adapter.setItems(items); - recyclerView.setAdapter(adapter); - ll.addView(recyclerView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) {{ - topMargin = ViewUtils.dp(16); - leftMargin = rightMargin = ViewUtils.dp(16); - }}); - } - - TextView manageButton = new TextView(context); - SpannableStringBuilder sb = SpannableStringBuilder.valueOf(context.getString(R.string.SettingsCloudManageSubscription)).append(" "); - Drawable dr = ContextCompat.getDrawable(context, R.drawable.external_link_outline_24); - int size = ViewUtils.dp(16); - dr.setBounds(0, 0, size, size); - sb.append("d", new TextColorImageSpan(dr, ViewUtils.dp(2f)), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); - manageButton.setText(sb); - manageButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - manageButton.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); - manageButton.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - manageButton.setGravity(Gravity.CENTER); - manageButton.setPadding(ViewUtils.dp(12), ViewUtils.dp(8), ViewUtils.dp(12), ViewUtils.dp(8)); - manageButton.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 16)); - CloudAPI.SubscriptionLevel finalLvl = lvl; - manageButton.setOnClickListener(v -> v.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(finalLvl.manageUrl)))); - ll.addView(manageButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(48)) {{ - leftMargin = rightMargin = ViewUtils.dp(16); - topMargin = bottomMargin = ViewUtils.dp(6); - }}); - } else { - ll.addView(new Space(context), new LinearLayout.LayoutParams(0, ViewUtils.dp(16))); - } + v.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + }); + ll.addView(manageButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(48)) {{ + leftMargin = rightMargin = ViewUtils.dp(16); + topMargin = bottomMargin = ViewUtils.dp(6); + }}); TextView buttonView = new TextView(context); buttonView.setText(R.string.SettingsCloudManageButtonLogOut); diff --git a/app/src/main/java/com/dark98/santoku/components/bed_menu/FileMenu.java b/app/src/main/java/com/dark98/santoku/components/bed_menu/FileMenu.java index 827c104..e8e2c30 100644 --- a/app/src/main/java/com/dark98/santoku/components/bed_menu/FileMenu.java +++ b/app/src/main/java/com/dark98/santoku/components/bed_menu/FileMenu.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.provider.MediaStore; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -15,7 +14,6 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; -import androidx.core.content.FileProvider; import androidx.core.graphics.ColorUtils; import androidx.recyclerview.widget.RecyclerView; @@ -33,20 +31,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import ru.ytkab0bp.eventbus.EventHandler; -import com.dark98.santoku.BeamServerData; -import com.dark98.santoku.BuildConfig; import com.dark98.santoku.MainActivity; import com.dark98.santoku.R; -import com.dark98.santoku.SetupActivity; import com.dark98.santoku.Santoku; -import com.dark98.santoku.cloud.CloudController; import com.dark98.santoku.components.BeamAlertDialogBuilder; import com.dark98.santoku.components.UnfoldMenu; import com.dark98.santoku.components.WebViewMenu; import com.dark98.santoku.config.ConfigObject; -import com.dark98.santoku.events.CloudFeaturesUpdatedEvent; -import com.dark98.santoku.events.CloudModelsRemainingCountUpdatedEvent; -import com.dark98.santoku.events.NeedDismissAIGeneratorMenu; import com.dark98.santoku.events.NeedDismissCalibrationsMenu; import com.dark98.santoku.events.NeedDismissSnackbarEvent; import com.dark98.santoku.events.NeedSnackbarEvent; @@ -61,11 +52,9 @@ import com.dark98.santoku.slic3r.Bed3D; import com.dark98.santoku.slic3r.Slic3rRuntimeError; import com.dark98.santoku.theme.BeamTheme; import com.dark98.santoku.theme.ThemesRepo; -import com.dark98.santoku.utils.Prefs; import com.dark98.santoku.utils.ViewUtils; import com.dark98.santoku.view.DividerView; import com.dark98.santoku.view.FadeRecyclerView; -import com.dark98.santoku.view.SegmentsView; import com.dark98.santoku.view.SnackbarsLayout; public class FileMenu extends ListBedMenu { @@ -126,29 +115,6 @@ public class FileMenu extends ListBedMenu { } }), new SpaceItem(portrait ? ViewUtils.dp(3) : 0, portrait ? 0 : ViewUtils.dp(3)))); - if (BeamServerData.isBoostyAvailable() && CloudController.needShowAIGenerator()) { - list.add(new BedMenuItem(R.string.MenuFileAIGenerator, R.drawable.picture_stack_outline_28).setShiny(true).onClick(view -> { - if (Prefs.getCloudAPIToken() == null || CloudController.getUserInfo() != null && CloudController.getMaxGeneratedModels() == 0) { - Context ctx = view.getContext(); - ctx.startActivity(new Intent(ctx, SetupActivity.class).putExtra(SetupActivity.EXTRA_CLOUD_PROFILE, true)); - return; - } - if (CloudController.getUserInfo() == null) { - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.LOADING, R.string.MenuFileAIGeneratorPleaseWaitSetup).tag(CloudController.USER_INFO_AI_GEN_TAG)); - ViewUtils.postOnMainThread(() -> { - if (CloudController.getUserInfo() == null) { - Santoku.EVENT_BUS.fireEvent(new NeedDismissSnackbarEvent(CloudController.USER_INFO_AI_GEN_TAG)); - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.ERROR, R.string.MenuFileAIGeneratorErrorNotLoadedUserAccount)); - } else { - fragment.showUnfoldMenu(new AIGeneratorMenu(), view); - } - }, 2500); - return; - } - - fragment.showUnfoldMenu(new AIGeneratorMenu(), view); - })); - } list.addAll(Arrays.asList( new BedMenuItem(R.string.MenuFileCalibrations, R.drawable.wrench_outline_28).setSingleLine(true).onClick(v -> { if (!fragment.getGlView().getRenderer().getBed().isValid()) { @@ -263,10 +229,7 @@ public class FileMenu extends ListBedMenu { public void onObjectsChanged(ObjectsListChangedEvent e) { ((BedMenuItem) adapter.getItems().get(1)).setEnabled(hasSelection()); adapter.notifyItemChanged(1); - - int i = 8 - (BeamServerData.isBoostyAvailable() && CloudController.needShowAIGenerator() ? 0 : 1); - ((BedMenuItem) adapter.getItems().get(i)).setEnabled(hasModel()); - adapter.notifyItemChanged(i); + updateModelItems(); } @EventHandler(runOnMainThread = true) @@ -275,147 +238,17 @@ public class FileMenu extends ListBedMenu { adapter.notifyItemChanged(1); } - @EventHandler(runOnMainThread = true) - public void onFeaturedUpdated(CloudFeaturesUpdatedEvent e) { - adapter.setItems(onCreateItems(wasPortrait)); - } - - public final static class AIGeneratorMenu extends UnfoldMenu { - private TextView remainingView; - private SegmentsView segmentsView; - - @Override - public int getRequestedSize(FrameLayout into, boolean portrait) { - return (int) (portrait ? ViewUtils.dp(52) + ViewUtils.dp(60) * 2 + ViewUtils.dp(28) + ViewUtils.dp(18) + ViewUtils.dp(2) : into.getWidth() * 0.6f); + private void updateModelItems() { + int idx = -1; + for (int j = adapter.getItems().size() - 1; j >= 0; j--) { + if (adapter.getItems().get(j) instanceof BedMenuItem) { + idx = j; + break; + } } - - @Override - protected View onCreateView(Context ctx, boolean portrait) { - LinearLayout ll = new LinearLayout(ctx); - ll.setOrientation(LinearLayout.VERTICAL); - - RecyclerView rv = new FadeRecyclerView(ctx); - rv.setOverScrollMode(View.OVER_SCROLL_NEVER); - SimpleRecyclerAdapter adapter = new SimpleRecyclerAdapter(); - adapter.setItems(Arrays.asList( - new PreferenceItem().setIcon(R.drawable.camera_outline_28).setTitle(ctx.getString(R.string.MenuFileAIGeneratorFromCamera)).setOnClickListener(v -> { - if (CloudController.getGeneratedModels() >= CloudController.getMaxGeneratedModels()) { - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.ERROR, R.string.MenuFileAIGeneratorNoGenerationsLeft)); - return; - } - if (MainActivity.IS_GENERATING_AI_MODEL) { - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.WARNING, R.string.MenuFileAIGeneratorAlreadyGenerating)); - return; - } - if (ctx instanceof MainActivity) { - try { - MainActivity.aiTempFile = File.createTempFile("ai_capture", ".jpg"); - Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); - i.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(ctx, BuildConfig.APPLICATION_ID + ".provider", MainActivity.aiTempFile)); - i.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - ((MainActivity) ctx).startActivityForResult(i, MainActivity.REQUEST_CODE_AI_GENERATOR_TAKE_PHOTO); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }), - new PreferenceItem().setIcon(R.drawable.picture_outline_28).setTitle(ctx.getString(R.string.MenuFileAIGeneratorFromGallery)).setOnClickListener(v -> { - if (CloudController.getGeneratedModels() >= CloudController.getMaxGeneratedModels()) { - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.ERROR, R.string.MenuFileAIGeneratorNoGenerationsLeft)); - return; - } - if (MainActivity.IS_GENERATING_AI_MODEL) { - Santoku.EVENT_BUS.fireEvent(new NeedSnackbarEvent(SnackbarsLayout.Type.WARNING, R.string.MenuFileAIGeneratorAlreadyGenerating)); - return; - } - if (ctx instanceof MainActivity) { - Intent intent = new Intent(); - intent.setType("image/*"); - intent.setAction(Intent.ACTION_GET_CONTENT); - ((MainActivity) ctx).startActivityForResult(Intent.createChooser(intent, ""), MainActivity.REQUEST_CODE_AI_GENERATOR_CHOOSE_PHOTO); - } - }) - )); - rv.setAdapter(adapter); - ll.addView(rv, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f)); - - ll.addView(new DividerView(ctx), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(1f))); - - remainingView = new TextView(ctx); - remainingView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); - remainingView.setGravity(Gravity.CENTER); - remainingView.setTextColor(ThemesRepo.getColor(android.R.attr.textColorSecondary)); - ll.addView(remainingView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(18)) {{ - topMargin = ViewUtils.dp(8); - }}); - - segmentsView = new SegmentsView(ctx) { - @Override - protected int onGetColor(int i) { - return i == 1 ? ThemesRepo.getColor(android.R.attr.textColorSecondary) : ThemesRepo.getColor(android.R.attr.colorAccent); - } - }; - ll.addView(segmentsView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(12)) {{ - leftMargin = rightMargin = ViewUtils.dp(12); - topMargin = bottomMargin = ViewUtils.dp(8); - }}); - updateRemaining(); - - ll.addView(new DividerView(ctx), new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(1f))); - - LinearLayout toolbar = new LinearLayout(ctx); - toolbar.setPadding(ViewUtils.dp(12), 0, ViewUtils.dp(12), 0); - toolbar.setOrientation(LinearLayout.HORIZONTAL); - toolbar.setGravity(Gravity.CENTER_VERTICAL); - toolbar.setBackground(ViewUtils.createRipple(ThemesRepo.getColor(android.R.attr.colorControlHighlight), 0)); - toolbar.setOnClickListener(v -> dismiss()); - - ImageView icon = new ImageView(ctx); - icon.setImageResource(R.drawable.arrow_left_outline_28); - icon.setColorFilter(ThemesRepo.getColor(android.R.attr.textColorSecondary)); - toolbar.addView(icon, new LinearLayout.LayoutParams(ViewUtils.dp(28), ViewUtils.dp(28))); - - TextView title = new TextView(ctx); - title.setText(R.string.MenuOrientationPositionBack); - title.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - title.setTextColor(ThemesRepo.getColor(android.R.attr.textColorPrimary)); - toolbar.addView(title, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) {{ - leftMargin = ViewUtils.dp(12); - }}); - ll.addView(toolbar, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewUtils.dp(52))); - return ll; - } - - @Override - protected void onCreate() { - super.onCreate(); - - Santoku.EVENT_BUS.registerListener(this); - ViewUtils.postOnMainThread(() -> segmentsView.startAnimation(), 50); - } - - @EventHandler(runOnMainThread = true) - public void onDismiss(NeedDismissAIGeneratorMenu e) { - dismiss(); - } - - @EventHandler(runOnMainThread = true) - public void onRemainingUpdated(CloudModelsRemainingCountUpdatedEvent e) { - updateRemaining(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - - Santoku.EVENT_BUS.unregisterListener(this); - } - - private void updateRemaining() { - int rev = CloudController.getMaxGeneratedModels() - CloudController.getGeneratedModels(); - remainingView.setText(Santoku.INSTANCE.getString(R.string.MenuFileAIGeneratorRemaining, rev, CloudController.getMaxGeneratedModels())); - segmentsView.setValues(new float[]{0, rev / (float) CloudController.getMaxGeneratedModels(), 1}); + if (idx != -1) { + ((BedMenuItem) adapter.getItems().get(idx)).setEnabled(hasModel()); + adapter.notifyItemChanged(idx); } } diff --git a/app/src/main/java/com/dark98/santoku/events/BeamServerDataUpdatedEvent.java b/app/src/main/java/com/dark98/santoku/events/BeamServerDataUpdatedEvent.java deleted file mode 100644 index 23508af..0000000 --- a/app/src/main/java/com/dark98/santoku/events/BeamServerDataUpdatedEvent.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.dark98.santoku.events; - -import ru.ytkab0bp.eventbus.Event; - -@Event -public class BeamServerDataUpdatedEvent {} diff --git a/app/src/main/java/com/dark98/santoku/events/CloudFeaturesUpdatedEvent.java b/app/src/main/java/com/dark98/santoku/events/CloudFeaturesUpdatedEvent.java deleted file mode 100644 index 2452f21..0000000 --- a/app/src/main/java/com/dark98/santoku/events/CloudFeaturesUpdatedEvent.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.dark98.santoku.events; - -import ru.ytkab0bp.eventbus.Event; - -@Event -public class CloudFeaturesUpdatedEvent {} diff --git a/app/src/main/java/com/dark98/santoku/events/CloudModelsRemainingCountUpdatedEvent.java b/app/src/main/java/com/dark98/santoku/events/CloudModelsRemainingCountUpdatedEvent.java deleted file mode 100644 index 65aead1..0000000 --- a/app/src/main/java/com/dark98/santoku/events/CloudModelsRemainingCountUpdatedEvent.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.dark98.santoku.events; - -import ru.ytkab0bp.eventbus.Event; - -@Event -public class CloudModelsRemainingCountUpdatedEvent {} diff --git a/app/src/main/java/com/dark98/santoku/events/NeedDismissAIGeneratorMenu.java b/app/src/main/java/com/dark98/santoku/events/NeedDismissAIGeneratorMenu.java deleted file mode 100644 index a9ee98a..0000000 --- a/app/src/main/java/com/dark98/santoku/events/NeedDismissAIGeneratorMenu.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.dark98.santoku.events; - -import ru.ytkab0bp.eventbus.Event; - -@Event -public class NeedDismissAIGeneratorMenu {} \ No newline at end of file diff --git a/app/src/main/java/com/dark98/santoku/fragment/SettingsFragment.java b/app/src/main/java/com/dark98/santoku/fragment/SettingsFragment.java index 19e0f04..c0cc6ae 100644 --- a/app/src/main/java/com/dark98/santoku/fragment/SettingsFragment.java +++ b/app/src/main/java/com/dark98/santoku/fragment/SettingsFragment.java @@ -20,15 +20,14 @@ import java.util.Collections; import java.util.List; import ru.ytkab0bp.eventbus.EventHandler; -import com.dark98.santoku.BeamServerData; import com.dark98.santoku.R; import com.dark98.santoku.SetupActivity; import com.dark98.santoku.Santoku; import com.dark98.santoku.components.BeamAlertDialogBuilder; import com.dark98.santoku.components.BeamColorPickerPopUp; import com.dark98.santoku.config.ConfigObject; -import com.dark98.santoku.events.BeamServerDataUpdatedEvent; import com.dark98.santoku.events.CloudUserInfoUpdatedEvent; +import com.dark98.santoku.cloud.CloudController; import com.dark98.santoku.recycler.PreferenceItem; import com.dark98.santoku.theme.BeamTheme; import com.dark98.santoku.theme.ThemesRepo; @@ -46,7 +45,7 @@ public class SettingsFragment extends ProfileListFragment { @Override protected List getConfigItems() { return Arrays.asList( - BeamServerData.isCloudAvailable() ? new OptionElement(SPECIAL_TYPE_CLOUD_HEADER).setOnClick(() -> { + CloudController.hasAccountFeatures() ? new OptionElement(SPECIAL_TYPE_CLOUD_HEADER).setOnClick(() -> { Activity act = (Activity) getContext(); act.startActivity(new Intent(act, SetupActivity.class).putExtra(SetupActivity.EXTRA_CLOUD_PROFILE, true)); }) : null, @@ -112,7 +111,7 @@ public class SettingsFragment extends ProfileListFragment { BeamTheme.LIGHT.colors.put(android.R.attr.colorAccent, Prefs.getAccentColor()); BeamTheme.DARK.colors.put(android.R.attr.colorAccent, Prefs.getAccentColor()); ThemesRepo.invalidate((Activity) getContext()); - recyclerView.getAdapter().notifyItemChanged(2 - (BeamServerData.isCloudAvailable() ? 0 : 1)); + recyclerView.getAdapter().notifyItemChanged(2 - (CloudController.hasAccountFeatures() ? 0 : 1)); } }) .setNegativeButtonText(getContext().getString(R.string.SettingsInterfaceColorReset)) @@ -135,7 +134,7 @@ public class SettingsFragment extends ProfileListFragment { Prefs.setRenderScale(variants[which]); dialog.dismiss(); // I'm too lazy to calculate real position for now - recyclerView.getAdapter().notifyItemChanged(4 - (BeamServerData.isCloudAvailable() ? 0 : 1)); + recyclerView.getAdapter().notifyItemChanged(4 - (CloudController.hasAccountFeatures() ? 0 : 1)); }) .show(); })), @@ -143,18 +142,6 @@ public class SettingsFragment extends ProfileListFragment { Activity act = (Activity) getContext(); act.startActivity(new Intent(act, SetupActivity.class).putExtra(SetupActivity.EXTRA_ABOUT, true)); }), - new OptionElement(R.drawable.telegram, getContext().getString(R.string.SettingsTelegram)).setColor(R.attr.telegramColor, false).setOnClick(() -> { - Activity act = (Activity) getContext(); - act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/ytkab0bp_channel"))); - }), - BeamServerData.isBoostyAvailable() ? new OptionElement(R.drawable.boosty, getContext().getString(R.string.SettingsBoosty)).setColor(R.attr.boostyColorTop, true).setOnClick(() -> { - Activity act = (Activity) getContext(); - act.startActivity(new Intent(act, SetupActivity.class).putExtra(SetupActivity.EXTRA_BOOSTY_ONLY, true)); - }) : null, - new OptionElement(R.drawable.k3d_logo_new_14, getContext().getString(R.string.SettingsK3D)).setColor(R.attr.k3dColor, true).setOnClick(() -> { - Activity act = (Activity) getContext(); - act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/K_3_D"))); - }), new OptionElement(R.drawable.refresh_outline_28, getContext().getString(R.string.SettingsResetToDefault)).setColor(R.attr.textColorNegative, false).setOnClick(() -> { Context ctx = getContext(); if (ctx instanceof Activity) { @@ -177,14 +164,9 @@ public class SettingsFragment extends ProfileListFragment { ); } - @EventHandler(runOnMainThread = true) - public void onDataUpdated(BeamServerDataUpdatedEvent e) { - setConfigItems(getConfigItems()); - } - @EventHandler(runOnMainThread = true) public void onUserInfoUpdated(CloudUserInfoUpdatedEvent e) { - if (BeamServerData.isCloudAvailable()) { + if (CloudController.hasAccountFeatures()) { recyclerView.getAdapter().notifyItemChanged(0); } } diff --git a/app/src/main/java/com/dark98/santoku/theme/BeamTheme.java b/app/src/main/java/com/dark98/santoku/theme/BeamTheme.java index 9e54aa1..c9d2181 100644 --- a/app/src/main/java/com/dark98/santoku/theme/BeamTheme.java +++ b/app/src/main/java/com/dark98/santoku/theme/BeamTheme.java @@ -20,10 +20,6 @@ public class BeamTheme { colors.put(R.attr.dividerContrastColor, 0xffcccccc); colors.put(R.attr.dialogBackground, 0xffffffff); colors.put(R.attr.switchThumbUncheckedColor, 0xffeef2f3); - colors.put(R.attr.boostyColorTop, 0xfff06e2a); - colors.put(R.attr.boostyColorBottom, 0xff884725); - colors.put(R.attr.telegramColor, 0xff27a7e7); - colors.put(R.attr.k3dColor, 0xff039045); colors.put(R.attr.modelHoverColor, 0xffffffff); colors.put(R.attr.textColorNegative, 0xffff464a); @@ -73,7 +69,6 @@ public class BeamTheme { colors.put(R.attr.bedContourlinesColor, 0x40ffffff); colors.put(R.attr.backgroundColorTop, 0xff292929); colors.put(R.attr.backgroundColorBottom, 0xff181818); - colors.put(R.attr.boostyColorBottom, 0xff884725); colors.put(R.attr.xTrackColor, 0xffee0000); colors.put(R.attr.yTrackColor, 0xff00ee00); diff --git a/app/src/main/java/com/dark98/santoku/utils/Prefs.java b/app/src/main/java/com/dark98/santoku/utils/Prefs.java index 2f2ad1d..fe1a4d0 100644 --- a/app/src/main/java/com/dark98/santoku/utils/Prefs.java +++ b/app/src/main/java/com/dark98/santoku/utils/Prefs.java @@ -47,31 +47,6 @@ public class Prefs { mPrefs.edit().putBoolean("scale_linked", v).apply(); } - public static long getLastCheckedInfo() { - return mPrefs.getLong("last_checked_info", 0); - } - - public static void setLastCheckedInfo() { - mPrefs.edit().putLong("last_checked_info", System.currentTimeMillis()).apply(); - } - - // Only used for displaying Boosty info, nothing more - public static boolean isRussianIP() { - return mPrefs.getBoolean("russian_ip", false); - } - - public static void setRussianIP(boolean v) { - mPrefs.edit().putBoolean("russian_ip", v).apply(); - } - - public static void setBeamServerData(String data) { - mPrefs.edit().putString("beam_server_data", data).apply(); - } - - public static String getBeamServerData() { - return mPrefs.getString("beam_server_data", "{}"); - } - public static int getCameraControlMode() { return mPrefs.getInt("camera_control_mode", mPrefs.getBoolean("rotation_enabled", true) ? CAMERA_CONTROL_MODE_ROTATE_MOVE : CAMERA_CONTROL_MODE_MOVE_ONLY); } @@ -161,40 +136,6 @@ public class Prefs { e.apply(); } - public static int getCloudCachedUsedModels() { - return mPrefs.getInt("cloud_cached_models_used", 0); - } - - public static int getCloudCachedMaxModels() { - return mPrefs.getInt("cloud_cached_models_max", 50); - } - - public static void setCloudCachedUsedMaxModels(int used, int max) { - mPrefs.edit().putInt("cloud_cached_models_used", used).putInt("cloud_cached_models_max", max).apply(); - } - - public static String getCloudCachedUserFeatures() { - return mPrefs.getString("cloud_cached_user_features", null); - } - - public static void setCloudCachedUserFeatures(String features) { - SharedPreferences.Editor e = mPrefs.edit(); - if (features == null) { - e.remove("cloud_cached_user_features"); - } else { - e.putString("cloud_cached_user_features", features); - } - e.apply(); - } - - public static long getCloudLastFeaturesSync() { - return mPrefs.getLong("cloud_last_features_sync", 0); - } - - public static void setCloudLastFeaturesSync(long ls) { - mPrefs.edit().putLong("cloud_last_features_sync", ls).apply(); - } - public static long getCloudLastSync() { return mPrefs.getLong("cloud_last_sync", 0); } diff --git a/app/src/main/java/com/dark98/santoku/view/BoostySubsView.java b/app/src/main/java/com/dark98/santoku/view/BoostySubsView.java deleted file mode 100644 index d599df3..0000000 --- a/app/src/main/java/com/dark98/santoku/view/BoostySubsView.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.dark98.santoku.view; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.text.TextPaint; -import android.text.TextUtils; -import android.util.SparseArray; -import android.view.View; - -import androidx.core.math.MathUtils; - -import java.util.ArrayList; -import java.util.List; - -import com.dark98.santoku.R; -import com.dark98.santoku.theme.ThemesRepo; -import com.dark98.santoku.utils.ViewUtils; - -public class BoostySubsView extends View { - private TextPaint paint = new TextPaint(); - - private List strings = new ArrayList<>(); - private SparseArray ellipsizedStrings = new SparseArray<>(); - private int index; - private float progress; - private long lastUpdated; - private int firstHeight; - - private Rect rect = new Rect(); - - public BoostySubsView(Context context) { - super(context); - - paint.setTextSize(ViewUtils.dp(20)); - paint.setTypeface(ViewUtils.getTypeface(ViewUtils.ROBOTO_MEDIUM)); - updateColors(); - } - - public void setStrings(List strings) { - this.strings = strings; - ellipsizedStrings.clear(); - index = 0; - progress = 0; - if (!strings.isEmpty()) { - String str = strings.get(index); - paint.getTextBounds(str, 0, str.length(), rect); - firstHeight = rect.height(); - } - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - long dt = Math.min(16, System.currentTimeMillis() - lastUpdated); - lastUpdated = System.currentTimeMillis(); - if (!strings.isEmpty()) { - float tY = (ViewUtils.dp(24) + firstHeight) * progress; - canvas.save(); - canvas.translate(0, -tY); - float halfHeight = getHeight() / 2f; - int y = 0; - - int i = index; - while (y <= getHeight() + tY) { - int j = i; - while (j < 0) j += strings.size(); - while (j >= strings.size()) j -= strings.size(); - - CharSequence str = ellipsizedStrings.get(j); - if (str == null) { - ellipsizedStrings.set(j, str = TextUtils.ellipsize(strings.get(j), paint, getWidth() - getPaddingLeft() - getPaddingRight(), TextUtils.TruncateAt.END)); - } - - paint.getTextBounds(str.toString(), 0, str.length(), rect); - float highlight = (1f - Math.abs((y - tY - firstHeight / 2f - halfHeight) / halfHeight)); - highlight = MathUtils.clamp(highlight, 0, 1); - paint.setAlpha((int) (0xFF * highlight)); - - float x = (getWidth() - rect.width()) / 2f; - canvas.drawText(str, 0, str.length(), x, y, paint); - - y += rect.height() + ViewUtils.dp(24); - i++; - } - - canvas.restore(); - - progress += dt / 2000f; - if (progress > 1) { - progress -= 1f; - index++; - index %= strings.size(); - - String str = strings.get(index); - paint.getTextBounds(str, 0, str.length(), rect); - firstHeight = rect.height(); - } - invalidate(); - } - } - - public void updateColors() { - paint.setColor(ThemesRepo.getColor(R.attr.textColorOnAccent)); - invalidate(); - } -} diff --git a/app/src/main/res/drawable/boosty.xml b/app/src/main/res/drawable/boosty.xml deleted file mode 100644 index 6c493f1..0000000 --- a/app/src/main/res/drawable/boosty.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/box_heart_outline_28.xml b/app/src/main/res/drawable/box_heart_outline_28.xml deleted file mode 100644 index 1fffd7b..0000000 --- a/app/src/main/res/drawable/box_heart_outline_28.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/k3d_logo_new_14.png b/app/src/main/res/drawable/k3d_logo_new_14.png deleted file mode 100644 index bf8924521856ca49d7efc5b9913528b3ea740fef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3923 zcmcgvdsLEX8visas|niLnZ`=3(`=r08f&BRE@l@mXG>>O)YQb*ltxWWG!O+^o3*w~ zx||d%q|2)LA(>-nsECd!V=AZ#rYV*hDhP-QAA-Q*%$YO0|1bXWo%cKMU+?ogzuWV# z?}Gd{uHUvE0Dz5w0mn`OfVKJ88n9hsJ{Iu(I`gqEE#Nd305)u1{;c{&NJ{_!UmbYN zHx&O+KG?$eG1zKR>f$Vb5Pf1ihb*c4FhwmF|?`z>HlZ4|^ty-j7bI zb*uQ0mjEikiigoM&Q{=7{Mk|9mOlU--f0B@|F8i78}rLH1z6(ZJg+ZM6zN$BVle5e z8K4KXCBLGvKbwoZThlCBT5ImqIsmZ!3IKNA0)Weh&At2oUw9VskM~Dr*MlY74I+{h zN0zh}IhcA9C-UEZN>|?WEa&aUc=aWo;pCOX-?5ui&=kVfnrfUzG<`KHiF`1ly`eh_(p-{I!!0h(#65M>M@~k8!^%3%8h~(C?duV~v{rP+A5*kBM15VV|e7sqHEGt3F zjelhSS4<--8cb~zU*;ljj)^b~FyLm4yT=rNhW9%lTi0_o$PL@mu*|CWO^_0Mwp znRSpf8KL1DWy~0~sZNEdAh5v{SjoktWt3T8hQ^n8ra|}NVKPZBT7);Ztj2%s^Vzsy z?zIstdFMz*;{O_-R9j!E^<+{K4oMKU_Tb`0U!lT34G!s1Y4f2pCu4n%@GA<>E zH#(PI9VP32XGf7M3hWO&7MJUc4LQ5`8%z`+Hi-kto~ANcmyqLaz1Zi5mU0TNN&%-` z%ovujTm^Z2yx?AO7u7H6?!HpcA*aXxpN_A0TU@u7i(!cyID&vAd0Ot<#t>AIncs~d z@*v*Nd$FxtuMiqs(%Yxg*-$&}?f7kk!}qM`F`bT!ziap<)7h%Rtr30H79&hW@zW3`*E?B87k2S)5%kUhS+S`qO!Q){o;0JW2!|O!UvKd zsd1k|uGvs0jUs2o&D=_&pooizI837~b`JtHE;)iJ;_aT}18|U}a^mr+Zwz;rWy=9` z_Mmaq3h{?d6V9$uBk5_$7rdAFg*QgPdb2eS@7sz4rRQcU9ONYDFYe}Oia)nH;IpM!~oz0t7&ki>yt=VkFEz&ufTsQ zlho+NnEB#!9@dwc%ZBG%Cn}WFHq5$cckW9>Hl$u~p$C?kv2DRT@+(PoGnILc&!EL0 z;*w+^akbGiVZwWl5t0P*uy(#i3p)%+%68!aD(TDw=c$paoDcvt!Ixu&#EdT6Zf(5CTeWm z%vF{4Vv)Kedc;lGWwoU7kcMY^)ZH=iRCP5=zu;?-Ctl}x4P-lR>zXC4gr#p{(l0od zj`~)ftjm5P|2G=g8lp730Eebr2O>S`^AkP01{@f=IZR#wl~%=#$($EYg>b~#-1|88 zth33=(kW?qp)o^mi((P<*g;s$!wg8bkCGC!-_}KjSAC)^lzNyJw@ zk;;+0*hiuvHAuLa>ltJAq|Xu_>W?Ui$y8rA%SVRg9ju?A)WCqVE3}iDHLx#KXaYj= Wq$$-{dxm*S1_F-<9eaKxHupcVj`pko diff --git a/app/src/main/res/drawable/telegram.xml b/app/src/main/res/drawable/telegram.xml deleted file mode 100644 index 73a08ff..0000000 --- a/app/src/main/res/drawable/telegram.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 07bed12..a9c93c4 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -16,19 +16,6 @@ Файл содержит более 500к треугольников. Нарезка может быть медленной. Загрузка файла… Убрать модель - Модель\nпо фото - Пожалуйста, подождите… - Ошибка: данные о пользователе пока не загружены. - Сделать фото - Выбрать из галереи - Осталось: %d / %d генераций - Загрузка изображения… - Обработка изображения… - Скачивание модели… - Не удалось сгенерировать модель - Модель сохранена как %s. - Не осталось генераций. - Уже генерируется другая модель. Калибров. K3D Linear Advance Калибровка Linear/Pressure Advance @@ -149,8 +136,6 @@ Вам необходимо настроить репозитории или использовать пользовательский профиль. Профили не настроены Вы должны выбрать хотя бы один профиль. - Поддерживается этими замечательными людьми на Boosty: - Подписаться на Boosty Далее Похоже всё настроено.\nПросто нажмите завершить! Завершить @@ -163,9 +148,6 @@ Это действие не может быть отменено. Сохранить Сохранить профиль? - Boosty разработчика - Telegram разработчика - Чат K3D Интерфейс Тема Системная @@ -176,7 +158,7 @@ Масштаб разрешения 3D Может увеличить производительность путём снижения разрешения О приложении - v%s\nОсновано на PrusaSlicer\n\nCreated by YTKAB0BP + v%s\nОсновано на PrusaSlicer & SliceBeam\n\nCreated by Dark98 %s - Копия Клон. текущий Удалить текущий @@ -184,20 +166,10 @@ Загрузка… Нажмите для управления Нажмите чтобы узнать больше - Аккаунт Beam 3D + Аккаунт Santoku Даёт следующие преимущества: - Ранний доступ - Вы можете скачать ранние сборки из чата Telegram для подписчиков Облачная синхронизация профилей Храните свои профили в облаке Beam - ИИ генератор моделей - %1$d моделей по фото в месяц - Slice Beam может оставаться бесплатным для всех - Ваш ник будет написан в списке поддержавших.\nСпасибо за вашу поддержку! - При подписке на данный уровень вы соглашаетесь с условиями обслуживания. - Уже подписаны? - Бесплатно - Вы подписаны Будет позже Условия обслуживания Настройки аккаунта @@ -206,9 +178,8 @@ Отменить авторизацию? Выйти Вошли как «%1$s» - Управление подпиской + Управление аккаунтом Список изменений - Выход данного обновления поддержали: Далее ОК Конвертация профилей, пожалуйста, подождите… @@ -229,4 +200,4 @@ Оставить локальные профили Да Нет - \ No newline at end of file + diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index e6a533a..7de400e 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -25,10 +25,6 @@ - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7572d94..034f7ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,19 +17,6 @@ File has more than 500k triangles. Processing could be slow. Loading file… Remove model - Model\nfrom photo - Please wait… - Error: user info not fetched yet. - Take a photo - Choose from gallery - Remaining: %d / %d generations - Uploading image… - Processing image… - Downloading model… - Failed to generate model - Saved model as %s. - No generations left. - Already generating another model. Calibrat. K3D Linear Advance Linear/Pressure Advance Calibration @@ -149,8 +136,6 @@ You must configure repositories or use a custom profile. No profiles configured You must select at least one profile. - Is supported by these awesome people on Boosty: - Subscribe at Boosty Next All seems to be configured.\nJust tap finish! Finish @@ -163,9 +148,6 @@ This action can not be undone. Save Save profile? - Developer\'s Boosty - Developer\'s Telegram - K3D Chat Interface Theme System @@ -176,7 +158,7 @@ 3D Resolution scale May improve performance by lowering resolution About app - v%s\nBased on PrusaSlicer\n\nCreated by YTKAB0BP + v%s\nBased on PrusaSlicer & SliceBeam\n\nCreated by Dark98 %s - Copy Clone current Delete current @@ -184,20 +166,10 @@ Loading… Tap to manage Tap to learn more - Beam 3D Account - Provides the following benefits: - Early access - You can download early builds from Telegram chat for subscribers + Santoku Account + Cloud account Cloud profiles sync Store your profiles in Beam Cloud - AI model generator - %1$d models from photo per month - Slice Beam can remain free for all - Your nickname will be written in the list of supporters.\nThanks for your support! - By subscribing to this level you accept terms of service. - Already subscribed? - Free - You are subscribed Will be later Terms of service Account settings @@ -206,10 +178,15 @@ Cancel login? Log out Logged in as «%1$s» - Manage subscription + Manage Account + Sign up + Email + Display name + Password + Please fill in all fields + Sign up failed + Show password Changelog - Boosty - The release of this update was supported by: Next OK Converting profiles, please wait… @@ -230,4 +207,4 @@ Keep local profiles Yes No - \ No newline at end of file + diff --git a/build.gradle b/build.gradle index 8bb264a..7fa1dc7 100644 --- a/build.gradle +++ b/build.gradle @@ -19,4 +19,135 @@ allprojects { task clean(type: Delete) { delete rootProject.buildDir -} \ No newline at end of file +} + +def loadLocalProperties() { + def props = new Properties() + def propsFile = rootProject.file("local.properties") + if (propsFile.exists()) { + propsFile.withInputStream { props.load(it) } + } + return props +} + +def resolveSdkDir() { + def props = loadLocalProperties() + return props.getProperty("sdk.dir") ?: System.getenv("ANDROID_SDK_ROOT") ?: System.getenv("ANDROID_HOME") +} + +def isWindows = System.getProperty("os.name").toLowerCase().contains("windows") +def npmCmd = isWindows ? "npm.cmd" : "npm" + +def findWindowsNpm() { + def candidates = [] + def pathEnv = System.getenv("PATH") ?: "" + pathEnv.split(";").each { p -> + if (!p) return + def cmd = new File(p, "npm.cmd") + if (cmd.exists()) candidates << cmd + def exe = new File(p, "npm.exe") + if (exe.exists()) candidates << exe + } + def nvmHome = System.getenv("NVM_HOME") + def nvmSymlink = System.getenv("NVM_SYMLINK") + if (nvmSymlink) { + def cmd = new File(nvmSymlink, "npm.cmd") + if (cmd.exists()) candidates << cmd + } + if (nvmHome) { + def current = new File(nvmHome, "current") + if (current.exists()) { + def cmd = new File(current, "npm.cmd") + if (cmd.exists()) candidates << cmd + } + def versions = new File(nvmHome) + if (versions.exists()) { + versions.listFiles()?.findAll { it.isDirectory() }?.each { v -> + def cmd = new File(v, "npm.cmd") + if (cmd.exists()) candidates << cmd + } + } + } + def appData = System.getenv("APPDATA") + if (appData) { + def cmd = new File(appData, "npm\\npm.cmd") + if (cmd.exists()) candidates << cmd + } + def programFiles = System.getenv("ProgramFiles") + if (programFiles) { + def cmd = new File(programFiles, "nodejs\\npm.cmd") + if (cmd.exists()) candidates << cmd + } + def localAppData = System.getenv("LOCALAPPDATA") + if (localAppData) { + def nvmLocal = new File(localAppData, "nvm") + if (nvmLocal.exists()) { + nvmLocal.listFiles()?.findAll { it.isDirectory() }?.each { v -> + def cmd = new File(v, "npm.cmd") + if (cmd.exists()) candidates << cmd + } + } + } + return candidates.isEmpty() ? null : candidates.first().absolutePath +} + +tasks.register("startBackend", Exec) { + workingDir "${rootDir}/backend" + if (isWindows) { + doFirst { + def npmPath = (project.findProperty("npmPath") ?: System.getenv("NPM_PATH"))?.toString() + if (!npmPath) { + npmPath = findWindowsNpm() + } + if (!npmPath) { + def out = new ByteArrayOutputStream() + exec { + commandLine "cmd", "/c", "where.exe", "npm" + standardOutput = out + errorOutput = out + ignoreExitValue = true + } + def line = out.toString().readLines().find { it.toLowerCase().endsWith("npm.cmd") || it.toLowerCase().endsWith("npm.exe") } + if (line) { + npmPath = line.trim() + } + } + if (!npmPath) { + throw new GradleException("npm not found. Set -PnpmPath=... or ensure npm is visible to cmd.exe. If using nvm, try your NVM_HOME version's npm.cmd.") + } + def nodeModules = new File(workingDir, "node_modules") + if (!nodeModules.exists()) { + exec { + workingDir "${rootDir}/backend" + commandLine "cmd", "/c", npmPath, "install" + } + } + commandLine "cmd", "/c", "start", "\"\"", npmPath, "start" + } + } else { + doFirst { + def nodeModules = new File(workingDir, "node_modules") + if (!nodeModules.exists()) { + exec { + workingDir "${rootDir}/backend" + commandLine "sh", "-c", "${npmCmd} install" + } + } + commandLine "sh", "-c", "${npmCmd} start &" + } + } +} + +tasks.register("runBackendDebug") { + dependsOn(":app:installDebug", "startBackend") + doLast { + def sdkDir = resolveSdkDir() + if (!sdkDir) { + throw new GradleException("Missing sdk.dir in local.properties and ANDROID_SDK_ROOT/ANDROID_HOME is not set") + } + def adb = "${sdkDir}/platform-tools/adb" + (isWindows ? ".exe" : "") + exec { + commandLine adb, "shell", "am", "start", "-n", "com.dark98.santoku/.MainActivity" + } + } +}