mirror of
https://github.com/AndorsTrailRelease/andors-trail.git
synced 2026-01-22 03:09:26 +01:00
Pull Request #91: Android upgrade (15)
This commit is contained in:
@@ -2,12 +2,12 @@ apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
|
||||
compileSdkVersion 34
|
||||
compileSdkVersion 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.gpl.rpg.AndorsTrail"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 34
|
||||
targetSdkVersion 35
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
|
||||
@@ -8,17 +8,25 @@ import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
|
||||
public final class AndorsTrailApplication extends Application {
|
||||
|
||||
public static final boolean DEVELOPMENT_DEBUGRESOURCES = false;
|
||||
@@ -57,13 +65,45 @@ public final class AndorsTrailApplication extends Application {
|
||||
|
||||
public void setWindowParameters(Activity activity) {
|
||||
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
if (preferences.fullscreen) {
|
||||
activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
public void setFullscreenMode(Activity activity) {
|
||||
setFullscreenMode(preferences.fullscreen, activity.getWindow());
|
||||
}
|
||||
public static void setFullscreenMode(boolean fullscreen, Window window) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
|
||||
final WindowInsetsController insetsController = window.getInsetsController();
|
||||
if (insetsController != null) {
|
||||
insetsController.setSystemBarsBehavior(WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
int insetType = WindowInsets.Type.statusBars();
|
||||
if (fullscreen) {
|
||||
insetsController.hide(insetType);
|
||||
} else {
|
||||
insetsController.show(insetType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
activity.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
if (fullscreen) {
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
} else {
|
||||
window.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
public int getUsableTouchAreaInsetMask(){
|
||||
int i = 0;
|
||||
i |= WindowInsets.Type.displayCutout();
|
||||
i |= WindowInsets.Type.navigationBars();
|
||||
if (!preferences.fullscreen) {
|
||||
i |= WindowInsets.Type.statusBars();
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
//Get default locale at startup, as somehow it seems that changing the app's
|
||||
//configured locale impacts the value returned by Locale.getDefault() nowadays.
|
||||
private final Locale defaultLocale = Locale.getDefault();
|
||||
@@ -166,4 +206,18 @@ public final class AndorsTrailApplication extends Application {
|
||||
controllers = new ControllerContext(this, world);
|
||||
setup = new WorldSetup(world, controllers, getApplicationContext());
|
||||
}
|
||||
|
||||
public void setUsablePadding(View root) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
root.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
Insets bars = insets.getInsets(getUsableTouchAreaInsetMask());
|
||||
int left = Math.max(bars.left, v.getPaddingLeft());
|
||||
int top = Math.max(bars.top, v.getPaddingTop());
|
||||
int right = Math.max(bars.right, v.getPaddingRight());
|
||||
int bottom = Math.max(bars.bottom, v.getPaddingBottom());
|
||||
v.setPadding(left, top, right, bottom);
|
||||
return WindowInsets.CONSUMED;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ public final class Dialogs {
|
||||
CustomDialogFactory.show(d);
|
||||
}
|
||||
|
||||
@TargetApi(23)
|
||||
private static boolean hasPermissions(final Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (activity.getApplicationContext().checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
|
||||
|
||||
@@ -24,9 +24,7 @@ public final class AboutActivity extends AndorsTrailBaseActivity implements Imag
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.about);
|
||||
initializeView(this, R.layout.about, R.id.about_root);
|
||||
final Resources res = getResources();
|
||||
|
||||
final TextView tv = (TextView) findViewById(R.id.about_contents);
|
||||
|
||||
@@ -30,9 +30,7 @@ public final class ActorConditionInfoActivity extends AndorsTrailBaseActivity {
|
||||
|
||||
String conditionTypeID = getIntent().getData().getLastPathSegment();
|
||||
ActorConditionType conditionType = world.actorConditionsTypes.getActorConditionType(conditionTypeID);
|
||||
|
||||
setContentView(R.layout.actorconditioninfo);
|
||||
|
||||
initializeView(this, R.layout.actorconditioninfo, R.id.actorconditioninfo_root);
|
||||
|
||||
TextView tv = (TextView) findViewById(R.id.actorconditioninfo_title);
|
||||
tv.setText(conditionType.name);
|
||||
|
||||
@@ -2,6 +2,10 @@ package com.gpl.rpg.AndorsTrail.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
|
||||
@@ -19,5 +23,13 @@ public abstract class AndorsTrailBaseActivity extends Activity {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
app.setLocale(this);
|
||||
}
|
||||
protected void initializeView(Activity activity, @LayoutRes int layoutId, @IdRes int rootViewId) {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(activity);
|
||||
app.setWindowParameters(activity);
|
||||
activity.setContentView(layoutId);
|
||||
View root = activity.findViewById(rootViewId);
|
||||
app.setUsablePadding(root);
|
||||
app.setFullscreenMode(activity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package com.gpl.rpg.AndorsTrail.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
@@ -19,4 +24,13 @@ public abstract class AndorsTrailBaseFragmentActivity extends FragmentActivity {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
app.setLocale(this);
|
||||
}
|
||||
|
||||
protected void initializeView(Activity activity, @LayoutRes int layoutId, @IdRes int rootViewId) {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(activity);
|
||||
app.setWindowParameters(activity);
|
||||
activity.setContentView(layoutId);
|
||||
View root = activity.findViewById(rootViewId);
|
||||
app.setUsablePadding(root);
|
||||
app.setFullscreenMode(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,7 @@ public final class BulkSelectionInterface extends AndorsTrailBaseActivity implem
|
||||
interfaceType = BulkInterfaceType.valueOf(params.getString("interfaceType"));
|
||||
|
||||
int intialSelection = 1;
|
||||
|
||||
setContentView(R.layout.bulkselection);
|
||||
initializeView(this, R.layout.bulkselection, R.id.bulkselection_root);
|
||||
|
||||
// initialize UI variables
|
||||
TextView bulkselection_action_type = (TextView)findViewById(R.id.bulkselection_action_type);
|
||||
|
||||
@@ -75,13 +75,11 @@ public final class ConversationActivity
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
setContentView(R.layout.conversation);
|
||||
initializeView(this, R.layout.conversation, R.id.conversation_root);
|
||||
|
||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
setFinishOnTouchOutside(false);
|
||||
}
|
||||
setFinishOnTouchOutside(false);
|
||||
|
||||
replyGroup = new RadioGroup(this);
|
||||
replyGroup = new RadioGroup(this);
|
||||
replyGroup.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, ListView.LayoutParams.WRAP_CONTENT));
|
||||
statementList = (ListView) findViewById(R.id.conversation_statements);
|
||||
statementList.addFooterView(replyGroup);
|
||||
|
||||
@@ -38,10 +38,7 @@ public final class DisplayWorldMapActivity extends AndorsTrailBaseActivity {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
if (!app.isInitialized()) { finish(); return; }
|
||||
this.world = app.getWorld();
|
||||
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.displayworldmap);
|
||||
initializeView(this, R.layout.displayworldmap, R.id.worldmap_root);
|
||||
|
||||
displayworldmap_webview = (WebView) findViewById(R.id.displayworldmap_webview);
|
||||
displayworldmap_webview.setBackgroundColor(ThemeHelper.getThemeColor(this, R.attr.ui_theme_displayworldmap_bg_color));
|
||||
|
||||
@@ -29,10 +29,7 @@ public final class HeroinfoActivity extends AndorsTrailBaseFragmentActivity {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
if (!app.isInitialized()) { finish(); return; }
|
||||
this.world = app.getWorld();
|
||||
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.tabbedlayout);
|
||||
initializeView(this, R.layout.tabbedlayout, android.R.id.tabhost);
|
||||
|
||||
Resources res = getResources();
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public final class ItemInfoActivity extends AndorsTrailBaseActivity {
|
||||
boolean buttonEnabled = params.getBoolean("buttonEnabled");
|
||||
boolean moreButtonEnabled = params.getBoolean("moreActions");
|
||||
|
||||
setContentView(R.layout.iteminfo);
|
||||
initializeView(this, R.layout.iteminfo, R.id.iteminfo_root);
|
||||
|
||||
TextView tv = (TextView) findViewById(R.id.iteminfo_title);
|
||||
tv.setText(itemType.getName(world.model.player));
|
||||
|
||||
@@ -37,7 +37,7 @@ public final class LevelUpActivity extends AndorsTrailBaseActivity {
|
||||
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
setContentView(R.layout.levelup);
|
||||
initializeView(this, R.layout.levelup, R.id.levelup_root);
|
||||
|
||||
levelup_title = (TextView) findViewById(R.id.levelup_title);
|
||||
levelup_description = (TextView) findViewById(R.id.levelup_description);
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class LoadSaveActivity extends AndorsTrailBaseActivity implements O
|
||||
String loadsave = getIntent().getData().getLastPathSegment();
|
||||
isLoading = (loadsave.equalsIgnoreCase("load"));
|
||||
|
||||
setContentView(R.layout.loadsave);
|
||||
initializeView(this, R.layout.loadsave, R.id.loadsave_root);
|
||||
|
||||
TextView tv = (TextView) findViewById(R.id.loadsave_title);
|
||||
if (isLoading) {
|
||||
|
||||
@@ -36,8 +36,7 @@ public final class LoadingActivity extends AndorsTrailBaseActivity implements On
|
||||
setTheme(ThemeHelper.getBaseTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
app.setWindowParameters(this);
|
||||
setContentView(R.layout.startscreen);
|
||||
initializeView(this, R.layout.startscreen, R.id.startscreen_fragment_container);
|
||||
|
||||
TextView tv = (TextView) findViewById(R.id.startscreen_version);
|
||||
tv.setVisibility(View.GONE);
|
||||
|
||||
@@ -91,9 +91,9 @@ public final class MainActivity
|
||||
AndorsTrailPreferences preferences = app.getPreferences();
|
||||
this.world = app.getWorld();
|
||||
this.controllers = app.getControllerContext();
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.main);
|
||||
initializeView(this, R.layout.main, R.id.main_container);
|
||||
|
||||
mainview = (MainView) findViewById(R.id.main_mainview);
|
||||
statusview = (StatusView) findViewById(R.id.main_statusview);
|
||||
combatview = (CombatView) findViewById(R.id.main_combatview);
|
||||
|
||||
@@ -34,7 +34,7 @@ public final class MonsterEncounterActivity extends AndorsTrailBaseActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.monsterencounter);
|
||||
initializeView(this, R.layout.monsterencounter, R.id.monsterencounter_root);
|
||||
|
||||
CharSequence difficulty = getText(MonsterInfoActivity.getMonsterDifficultyResource(controllers, monster));
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public final class MonsterInfoActivity extends AndorsTrailBaseActivity {
|
||||
this.controllers = app.getControllerContext();
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
|
||||
setContentView(R.layout.monsterinfo);
|
||||
initializeView(this, R.layout.monsterinfo, R.id.monsterinfo_root);
|
||||
|
||||
monsterinfo_title = (TextView) findViewById(R.id.monsterinfo_title);
|
||||
monsterinfo_difficulty = (TextView) findViewById(R.id.monsterinfo_difficulty);
|
||||
|
||||
@@ -13,17 +13,16 @@ public final class Preferences extends PreferenceActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(ThemeHelper.getBaseTheme());
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
if (app.getPreferences().fullscreen) {
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else {
|
||||
getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
app.setWindowParameters(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
app.setFullscreenMode(this);
|
||||
|
||||
|
||||
app.setLocale(this);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,9 +23,8 @@ public final class ShopActivity extends AndorsTrailBaseFragmentActivity {
|
||||
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||
if (!app.isInitialized()) { finish(); return; }
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.tabbedlayout);
|
||||
initializeView(this, R.layout.tabbedlayout, android.R.id.tabhost);
|
||||
|
||||
final Resources res = getResources();
|
||||
|
||||
|
||||
@@ -31,9 +31,7 @@ public final class SkillInfoActivity extends AndorsTrailBaseActivity {
|
||||
final WorldContext world = app.getWorld();
|
||||
final Player player = world.model.player;
|
||||
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.skill_info_view);
|
||||
initializeView(this, R.layout.skill_info_view, R.id.skillinfo_root);
|
||||
|
||||
final Resources res = getResources();
|
||||
final Intent intent = getIntent();
|
||||
|
||||
@@ -21,6 +21,8 @@ import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
|
||||
import android.view.KeyEvent;
|
||||
@@ -49,9 +51,9 @@ public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity i
|
||||
final Resources res = getResources();
|
||||
TileManager tileManager = app.getWorld().tileManager;
|
||||
tileManager.setDensity(res);
|
||||
app.setWindowParameters(this);
|
||||
|
||||
setContentView(R.layout.startscreen);
|
||||
initializeView(this, R.layout.startscreen, R.id.startscreen_fragment_container);
|
||||
app.setFullscreenMode(this);
|
||||
|
||||
if (findViewById(R.id.startscreen_fragment_container) != null) {
|
||||
StartScreenActivity_MainMenu mainMenu = new StartScreenActivity_MainMenu();
|
||||
@@ -67,9 +69,11 @@ public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity i
|
||||
|
||||
|
||||
tv = (TextView) findViewById(R.id.startscreen_version);
|
||||
app.setUsablePadding(tv);
|
||||
tv.setText('v' + AndorsTrailApplication.CURRENT_VERSION_DISPLAY);
|
||||
|
||||
development_version = (TextView) findViewById(R.id.startscreen_dev_version);
|
||||
app.setUsablePadding((View) development_version.getParent());
|
||||
if (AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAMES) {
|
||||
development_version.setText(R.string.startscreen_incompatible_savegames);
|
||||
development_version.setVisibility(View.VISIBLE);
|
||||
@@ -96,6 +100,10 @@ public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity i
|
||||
}
|
||||
});
|
||||
}
|
||||
View titleLogo = findViewById(R.id.title_logo);
|
||||
if (titleLogo != null) {
|
||||
app.setUsablePadding(titleLogo);
|
||||
}
|
||||
|
||||
if (development_version.getVisibility() == View.VISIBLE) {
|
||||
development_version.setText(development_version.getText()
|
||||
@@ -112,7 +120,7 @@ public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity i
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, int[] grantResults) {
|
||||
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(this,
|
||||
|
||||
@@ -59,7 +59,6 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
updatePreferences(false);
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
|
||||
if (container != null) {
|
||||
container.removeAllViews();
|
||||
}
|
||||
@@ -196,7 +195,6 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
|
||||
}
|
||||
|
||||
@TargetApi(29)
|
||||
public void migrateDataOnDemand(final Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -232,7 +230,6 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
private static final int READ_EXTERNAL_STORAGE_REQUEST=1;
|
||||
private static final int WRITE_EXTERNAL_STORAGE_REQUEST=2;
|
||||
|
||||
@TargetApi(23)
|
||||
public static void checkAndRequestPermissions(final Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.activity.fragment;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -39,8 +40,7 @@ public class StartScreenActivity_NewGame extends Fragment {
|
||||
}
|
||||
|
||||
View root = inflater.inflate(R.layout.startscreen_newgame, container, false);
|
||||
|
||||
|
||||
|
||||
startscreen_enterheroname = (TextView) root.findViewById(R.id.startscreen_enterheroname);
|
||||
|
||||
new SpinnerEmulator(root, R.id.startscreen_mode_selector_button, R.array.startscreen_mode_selector, R.string.startscreen_game_mode) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class ActorConditionsTypeParser extends JsonCollectionParserFor<ActorConditionType> {
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonArrayParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class ConversationListParser extends JsonCollectionParserFor<Phrase> {
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonArrayParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class DropListParser extends JsonCollectionParserFor<DropList> {
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.gpl.rpg.AndorsTrail.model.item.ItemCategory;
|
||||
import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class ItemCategoryParser extends JsonCollectionParserFor<ItemCategory> {
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class ItemTypeParser extends JsonCollectionParserFor<ItemType> {
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.ConstRange;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
|
||||
public final class MonsterTypeParser extends JsonCollectionParserFor<MonsterType> {
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonArrayParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonCollectionParserFor;
|
||||
import com.gpl.rpg.AndorsTrail.resource.parsers.json.JsonFieldNames;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public final class QuestParser extends JsonCollectionParserFor<Quest> {
|
||||
private final TranslationLoader translationLoader;
|
||||
|
||||
@@ -16,7 +16,7 @@ import com.gpl.rpg.AndorsTrail.model.map.WorldMapSegment.WorldMapSegmentMap;
|
||||
import com.gpl.rpg.AndorsTrail.resource.TranslationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
import com.gpl.rpg.AndorsTrail.util.XmlResourceParserUtils;
|
||||
|
||||
public final class WorldMapParser {
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.json.JSONException;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.Pair;
|
||||
import android.util.Pair;
|
||||
|
||||
public abstract class JsonCollectionParserFor<T> extends JsonParserFor<Pair<String, T>> {
|
||||
public HashSet<String> parseRows(String input, HashMap<String, T> dest) {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
// Should really use android.util.Pair<> instead, but it is not available for API level 4 (Android 1.6).
|
||||
public final class Pair<T1, T2> {
|
||||
public final T1 first;
|
||||
public final T2 second;
|
||||
public Pair(T1 a, T2 b) {
|
||||
this.first = a;
|
||||
this.second = b;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -76,11 +75,8 @@ public class CustomDialogFactory {
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(R.layout.custom_dialog_title_icon);
|
||||
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||
if (((AndorsTrailApplication)context.getApplicationContext()).getPreferences().fullscreen) {
|
||||
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
} else {
|
||||
dialog.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
boolean fullscreen = ((AndorsTrailApplication) context.getApplicationContext()).getPreferences().fullscreen;
|
||||
AndorsTrailApplication.setFullscreenMode(fullscreen, dialog.getWindow());
|
||||
|
||||
setTitle(dialog, title, icon);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:padding="@dimen/dialog_margin"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/about_root"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/actorconditioninfo_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actorconditioninfo_title"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical" android:id="@+id/bulkselection_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bulkselection_itemname"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/conversation_root"
|
||||
>
|
||||
|
||||
<ListView
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/worldmap_root">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/iteminfo_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iteminfo_title"
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/dialog_margin" >
|
||||
android:padding="@dimen/dialog_margin"
|
||||
android:id="@+id/levelup_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/levelup_title"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/dialog_margin"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/loadsave_root"
|
||||
>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/monsterencounter_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/monsterencounter_title"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/monsterinfo_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/monsterinfo_title"
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/skillinfo_root">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/skillinfo_title"
|
||||
|
||||
258
AndorsTrail/tools/check_format_specifiers.py
Normal file
258
AndorsTrail/tools/check_format_specifiers.py
Normal file
@@ -0,0 +1,258 @@
|
||||
import re
|
||||
import os
|
||||
import argparse
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
def get_string_value_and_specifiers(filepath, key_name):
|
||||
"""
|
||||
Parses an XML strings file to find a specific key and its format specifiers.
|
||||
|
||||
Args:
|
||||
filepath (str): Path to the strings.xml file.
|
||||
key_name (str): The name of the string resource to find.
|
||||
|
||||
Returns:
|
||||
tuple: (string_value, set_of_specifiers) or (None, None) if key not found.
|
||||
Specifiers are returned as a set, e.g., {"%1$s", "%2$d"}.
|
||||
"""
|
||||
try:
|
||||
tree = ET.parse(filepath)
|
||||
root = tree.getroot()
|
||||
for string_tag in root.findall('string'):
|
||||
if string_tag.get('name') == key_name:
|
||||
value = string_tag.text if string_tag.text else ""
|
||||
# Regex to find format specifiers like %s, %d, %1$s, %2$d, etc.
|
||||
# It handles optional positional arguments (e.g., 1$) and type characters.
|
||||
specifiers = set(re.findall(r'%(?:(?:\d+\$)?(?:[sdfeoxXgGaAbhHc]|(?:\.\d[fd])))', value))
|
||||
return value, specifiers
|
||||
except ET.ParseError:
|
||||
print(f"Warning: Could not parse XML file: {filepath}")
|
||||
except FileNotFoundError:
|
||||
print(f"Warning: File not found: {filepath}")
|
||||
return None, None
|
||||
|
||||
def find_res_directories(project_root):
|
||||
"""
|
||||
Finds all 'res' directories within a project, typically in module roots.
|
||||
"""
|
||||
res_dirs = []
|
||||
for root_dir, dirs, _ in os.walk(project_root):
|
||||
if 'res' in dirs:
|
||||
res_dirs.append(os.path.join(root_dir, 'res'))
|
||||
if not res_dirs and os.path.basename(project_root) == 'res': # If project_root itself is a res dir
|
||||
res_dirs.append(project_root)
|
||||
return res_dirs
|
||||
|
||||
|
||||
def find_strings_files(res_dir_path, base_filename="strings.xml"):
|
||||
"""
|
||||
Finds all strings.xml files (or variants like strings-es.xml)
|
||||
within a given 'res' directory.
|
||||
"""
|
||||
strings_files = {} # lang_code -> filepath
|
||||
for dirpath, _, filenames in os.walk(res_dir_path):
|
||||
if "values" in os.path.basename(dirpath).lower(): # e.g., values, values-es, values-en-rGB
|
||||
for filename in filenames:
|
||||
if filename.startswith(os.path.splitext(base_filename)[0]) and filename.endswith(".xml"):
|
||||
full_path = os.path.join(dirpath, filename)
|
||||
# Determine language code from directory name (e.g., "values-es" -> "es")
|
||||
# or default if it's just "values"
|
||||
dir_name_parts = os.path.basename(dirpath).split('-')
|
||||
lang_code = "default" # For the base "values" folder
|
||||
if len(dir_name_parts) > 1:
|
||||
lang_code = "-".join(dir_name_parts[1:]) # Handles values-en-rUS correctly
|
||||
strings_files[lang_code] = full_path
|
||||
return strings_files
|
||||
|
||||
def find_non_escaped_percent(value):
|
||||
"""
|
||||
Finds non-escaped % characters in a string (not part of %% or a valid format specifier).
|
||||
Returns a list of indices where such % occur.
|
||||
"""
|
||||
# Find all % positions
|
||||
percent_indices = [m.start() for m in re.finditer(r'%', value)]
|
||||
# Find all valid format specifiers and %% positions
|
||||
valid_specifier_pattern = r'%(?:%|(?:\d+\$)?(?:[sdfeoxXgGaAbhHc]|(?:\.\d[fd])))'
|
||||
valid_matches = [m.span() for m in re.finditer(valid_specifier_pattern, value)]
|
||||
# Mark all indices covered by valid specifiers or %%
|
||||
covered_indices = set()
|
||||
for start, end in valid_matches:
|
||||
covered_indices.update(range(start, end))
|
||||
# Only report % indices not covered by valid specifiers or %%
|
||||
return [idx for idx in percent_indices if idx not in covered_indices]
|
||||
|
||||
def get_all_keys(filepath):
|
||||
"""
|
||||
Returns a list of all string resource keys in the given XML file.
|
||||
"""
|
||||
try:
|
||||
tree = ET.parse(filepath)
|
||||
root = tree.getroot()
|
||||
return [string_tag.get('name') for string_tag in root.findall('string') if string_tag.get('name')]
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
def find_used_keys_in_java(project_root):
|
||||
"""
|
||||
Scans all .java files under project_root for usages of string resource keys.
|
||||
Returns a set of keys found.
|
||||
"""
|
||||
key_pattern = re.compile(r'R\.string\.([a-zA-Z0-9_]+)')
|
||||
used_keys = set()
|
||||
for root, _, files in os.walk(project_root):
|
||||
for fname in files:
|
||||
if fname.endswith('.java'):
|
||||
try:
|
||||
with open(os.path.join(root, fname), encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
used_keys.update(key_pattern.findall(content))
|
||||
except Exception:
|
||||
pass
|
||||
return used_keys
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Check format specifier consistency across language files for a given string key."
|
||||
)
|
||||
parser.add_argument(
|
||||
"project_root",
|
||||
help="Path to the Android project's root directory (or a specific module's root directory)."
|
||||
)
|
||||
parser.add_argument(
|
||||
"res_root",
|
||||
help="Path to the some 'res' directory."
|
||||
)
|
||||
parser.add_argument(
|
||||
"key_name",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="The name of the string resource to check (e.g., 'skill_longdescription_evasion'). If omitted, checks all keys in the base language file."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--base_lang",
|
||||
default="default",
|
||||
help="The language code for the base/reference strings file (e.g., 'en', 'default' for values/strings.xml). Default is 'default'."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strings_filename",
|
||||
default="strings.xml",
|
||||
help="The base name of your strings files (default: strings.xml)."
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print(f"Using base language: '{args.base_lang}' from file '{args.strings_filename}'")
|
||||
print(f"Project root path: {args.project_root}\n")
|
||||
print(f"Project res path: {args.res_root}\n")
|
||||
|
||||
res_directories = find_res_directories(args.res_root)
|
||||
if not res_directories:
|
||||
print(f"Error: No 'res' directory found under {args.res_root}")
|
||||
return
|
||||
|
||||
all_strings_files = {}
|
||||
for res_dir in res_directories:
|
||||
all_strings_files.update(find_strings_files(res_dir, args.strings_filename))
|
||||
|
||||
if not all_strings_files:
|
||||
print(f"Error: No '{args.strings_filename}' files found in any 'res/values-*' directories under {args.res_root}.")
|
||||
return
|
||||
|
||||
base_file_path = all_strings_files.get(args.base_lang)
|
||||
if not base_file_path:
|
||||
if args.base_lang != "default" and all_strings_files.get("default"):
|
||||
print(f"Warning: Base language '{args.base_lang}' not found. Using 'default' (values/{args.strings_filename}) as base.")
|
||||
base_file_path = all_strings_files.get("default")
|
||||
args.base_lang = "default"
|
||||
else:
|
||||
print(f"Error: Base strings file for language '{args.base_lang}' not found.")
|
||||
print(f"Available language files found: {list(all_strings_files.keys())}")
|
||||
return
|
||||
|
||||
# If no key_name is provided, check only keys used in .java files
|
||||
if args.key_name is None:
|
||||
used_keys = find_used_keys_in_java(args.project_root)
|
||||
all_keys = set(get_all_keys(base_file_path))
|
||||
keys_to_check = sorted(list(all_keys & used_keys))
|
||||
if not keys_to_check:
|
||||
print('no keys to check')
|
||||
return
|
||||
else:
|
||||
keys_to_check = [args.key_name]
|
||||
|
||||
total_issues_found = 0
|
||||
file_error_counts = {}
|
||||
file_warning_counts = {}
|
||||
|
||||
for key_name in keys_to_check:
|
||||
base_value, base_specifiers = get_string_value_and_specifiers(base_file_path, key_name)
|
||||
if base_specifiers is None:
|
||||
continue
|
||||
|
||||
for lang_code, file_path in all_strings_files.items():
|
||||
if lang_code == args.base_lang:
|
||||
continue
|
||||
|
||||
current_value, current_specifiers = get_string_value_and_specifiers(file_path, key_name)
|
||||
if current_specifiers is None:
|
||||
continue
|
||||
|
||||
error_count = 0
|
||||
warning_count = 0
|
||||
|
||||
non_escaped_percent_indices = find_non_escaped_percent(current_value)
|
||||
if non_escaped_percent_indices:
|
||||
error_count += 1
|
||||
print(f"--- Language: {lang_code} (NON-ESCAPED % FOUND) ---")
|
||||
print(f"Key: {key_name}")
|
||||
print(f"File: {file_path}")
|
||||
print(f"Value: \"{current_value}\"")
|
||||
print(f"Non-escaped % at positions: {non_escaped_percent_indices}")
|
||||
print("-" * 20)
|
||||
|
||||
if current_specifiers != base_specifiers:
|
||||
missing_in_current = base_specifiers - current_specifiers
|
||||
extra_in_current = current_specifiers - base_specifiers
|
||||
|
||||
if extra_in_current:
|
||||
error_count += 1
|
||||
print(f"--- Language: {lang_code} (ISSUE FOUND) ---")
|
||||
print(f"Key: {key_name}")
|
||||
print(f"File: {file_path}")
|
||||
print(f"Value: \"{current_value}\"")
|
||||
print(f"Specifiers: {sorted(list(current_specifiers)) if current_specifiers else 'None'}")
|
||||
print(f"Expected specifiers (from base): {sorted(list(base_specifiers)) if base_specifiers else 'None'}")
|
||||
print(f" EXTRA in '{lang_code}': {sorted(list(extra_in_current))}")
|
||||
print("-" * 20)
|
||||
if missing_in_current:
|
||||
warning_count += 1
|
||||
print(f"--- Language: {lang_code} (WARNING: MISSING SPECIFIERS) ---")
|
||||
print(f"Key: {key_name}")
|
||||
print(f"File: {file_path}")
|
||||
print(f"Value: \"{current_value}\"")
|
||||
print(f"Specifiers: {sorted(list(current_specifiers)) if current_specifiers else 'None'}")
|
||||
print(f"Expected specifiers (from base): {sorted(list(base_specifiers)) if base_specifiers else 'None'}")
|
||||
print(f" MISSING in '{lang_code}': {sorted(list(missing_in_current))}")
|
||||
print("-" * 20)
|
||||
|
||||
if error_count:
|
||||
file_error_counts[file_path] = file_error_counts.get(file_path, 0) + error_count
|
||||
if warning_count:
|
||||
file_warning_counts[file_path] = file_warning_counts.get(file_path, 0) + warning_count
|
||||
|
||||
if file_error_counts or file_warning_counts:
|
||||
print("\nSummary of errors and warnings per file:")
|
||||
for file_path in sorted(set(list(file_error_counts.keys()) + list(file_warning_counts.keys()))):
|
||||
error_str = f"{file_error_counts.get(file_path, 0)} error(s)"
|
||||
warning_str = f"{file_warning_counts.get(file_path, 0)} warning(s)"
|
||||
print(f"{file_path}:\t {error_str:>5}, {warning_str:>5}")
|
||||
|
||||
total_errors = sum(file_error_counts.values())
|
||||
total_warnings = sum(file_warning_counts.values())
|
||||
print(f"\nTOTAL: {total_errors} error(s), {total_warnings} warning(s)")
|
||||
|
||||
if file_error_counts:
|
||||
exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user