mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-03 16:49:03 +00:00
Cloud/Backend Overhaul
Reverse Engineered a Backend Removed Boosty Stuff Removed Socials Stuff Removed Subscription Stuff Probably Some More
This commit is contained in:
@@ -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<String> 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<ConfigObject> EXPORTING_FILAMENTS;
|
||||
public static List<ConfigObject> EXPORTING_PRINTERS;
|
||||
|
||||
public static boolean IS_GENERATING_AI_MODEL;
|
||||
|
||||
public static File aiTempFile;
|
||||
|
||||
private static SparseArray<NavigationDelegate> 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<InputStream>() {
|
||||
@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 {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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<String> 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<ProfilesRepo, List<Slic3rConfigWrapper>> 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<SimpleRecyclerItem> 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<CloudSubscriptionLevel.LevelHolderView> {
|
||||
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<SimpleRecyclerItem> 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<CloudAPI.AuthToken>() {
|
||||
@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<View> {
|
||||
@@ -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<View> {
|
||||
|
||||
@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<String> 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<View> {
|
||||
private TextView buttonView;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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<UserInfo> callback);
|
||||
|
||||
/**
|
||||
* Gets user features
|
||||
* Creates a new account (email/password)
|
||||
*/
|
||||
@Method("user/getFeatures")
|
||||
void userGetFeatures(APICallback<UserFeatures> callback);
|
||||
@Method(requestType = RequestType.POST, value = "signup")
|
||||
void signup(@Arg("email") String email, @Arg("password") String password, @Arg("displayName") String displayName, APICallback<AuthToken> callback);
|
||||
|
||||
/**
|
||||
* Login with email/password
|
||||
*/
|
||||
@Method(requestType = RequestType.POST, value = "login")
|
||||
void login(@Arg("email") String email, @Arg("password") String password, APICallback<AuthToken> callback);
|
||||
|
||||
/**
|
||||
* Fetches sync state
|
||||
@@ -103,24 +104,6 @@ public interface CloudAPI extends APIRunner {
|
||||
@Method("sync/get")
|
||||
void syncGet(APICallback<String> callback);
|
||||
|
||||
/**
|
||||
* Generates 3D model from image
|
||||
* <p>
|
||||
* @param image Base64 encoded image
|
||||
* <p>
|
||||
* Requires authorization
|
||||
*/
|
||||
@Method(requestType = RequestType.POST, value = "models/generate")
|
||||
void modelsGenerate(@Arg("") String image, @Header("Content-Type") String type, APICallback<InputStream> callback);
|
||||
|
||||
/**
|
||||
* Gets remaining model generations count
|
||||
* <p>
|
||||
* Requires authorization
|
||||
*/
|
||||
@Method("models/getRemainingCount")
|
||||
void modelsGetRemainingCount(APICallback<ModelsRemainingCount> callback);
|
||||
|
||||
/**
|
||||
* Destroys token
|
||||
* <p>
|
||||
@@ -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<SubscriptionLevel> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<CloudAPI.ModelsRemainingCount>() {
|
||||
@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<CloudAPI.UserFeatures>() {
|
||||
@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) {
|
||||
|
||||
@@ -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<String> 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<String> list = new ArrayList<>(Santoku.SERVER_DATA.boostySubscribers);
|
||||
Collections.shuffle(list);
|
||||
subsView.setStrings(list);
|
||||
}
|
||||
pager.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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<SimpleRecyclerItem> 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<SimpleRecyclerItem> 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.dark98.santoku.events;
|
||||
|
||||
import ru.ytkab0bp.eventbus.Event;
|
||||
|
||||
@Event
|
||||
public class BeamServerDataUpdatedEvent {}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.dark98.santoku.events;
|
||||
|
||||
import ru.ytkab0bp.eventbus.Event;
|
||||
|
||||
@Event
|
||||
public class CloudFeaturesUpdatedEvent {}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.dark98.santoku.events;
|
||||
|
||||
import ru.ytkab0bp.eventbus.Event;
|
||||
|
||||
@Event
|
||||
public class CloudModelsRemainingCountUpdatedEvent {}
|
||||
@@ -1,6 +0,0 @@
|
||||
package com.dark98.santoku.events;
|
||||
|
||||
import ru.ytkab0bp.eventbus.Event;
|
||||
|
||||
@Event
|
||||
public class NeedDismissAIGeneratorMenu {}
|
||||
@@ -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<OptionElement> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<String> strings = new ArrayList<>();
|
||||
private SparseArray<CharSequence> 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<String> 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user