diff --git a/AndorsTrail/app/build.gradle b/AndorsTrail/app/build.gradle index f0b4b0ba5..a1c1fc9b1 100644 --- a/AndorsTrail/app/build.gradle +++ b/AndorsTrail/app/build.gradle @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java index 287b694f8..3613a6e74 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java @@ -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; + }); + } + } } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/Dialogs.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/Dialogs.java index 75a0e1c4e..9816764f7 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/Dialogs.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/Dialogs.java @@ -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 diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java index ceafb5ee1..fa8b38647 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AboutActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java index 6354edf6c..d2a9e0dfb 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseActivity.java index 83f8a4d07..598ff027a 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseActivity.java @@ -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); + } } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseFragmentActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseFragmentActivity.java index fc6f573f4..591192c68 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseFragmentActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/AndorsTrailBaseFragmentActivity.java @@ -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); + } } diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/BulkSelectionInterface.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/BulkSelectionInterface.java index 3c928623d..874591929 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/BulkSelectionInterface.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/BulkSelectionInterface.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java index 6837dd5ac..5a98e9c68 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/DisplayWorldMapActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/DisplayWorldMapActivity.java index f5a3a3687..f7c5ce397 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/DisplayWorldMapActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/DisplayWorldMapActivity.java @@ -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)); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java index ad4153624..6106cda38 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity.java @@ -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(); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java index 2750e844c..4fcc1719a 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java @@ -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)); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java index 3f9831aa5..5a891754f 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadSaveActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadSaveActivity.java index e2fb26f3d..183ed5afc 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadSaveActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadSaveActivity.java @@ -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) { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadingActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadingActivity.java index a8d9bc232..6def27a7e 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadingActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/LoadingActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MainActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MainActivity.java index 3ca1b476e..e2cf01ac2 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MainActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MainActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java index 5d11ea8a5..e50f2d28e 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java @@ -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)); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java index 219e60c15..e7f6ec22a 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java @@ -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); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/Preferences.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/Preferences.java index c524089cd..d46e704e0 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/Preferences.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/Preferences.java @@ -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 diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java index e1e76dbf8..235348917 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java @@ -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(); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/SkillInfoActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/SkillInfoActivity.java index b066d8ee8..acd1bcecc 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/SkillInfoActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/SkillInfoActivity.java @@ -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(); diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java index fd55984dc..64c7484a8 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java @@ -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, diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_MainMenu.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_MainMenu.java index ba424a9b2..bcfd8ed3f 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_MainMenu.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_MainMenu.java @@ -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) { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_NewGame.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_NewGame.java index 0705bce29..4794c61d6 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_NewGame.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/activity/fragment/StartScreenActivity_NewGame.java @@ -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) { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ActorConditionsTypeParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ActorConditionsTypeParser.java index 3ed83d905..90ee7fee6 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ActorConditionsTypeParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ActorConditionsTypeParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java index 215c984b2..e3c426399 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/DropListParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/DropListParser.java index bcb87337f..063a9ef5d 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/DropListParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/DropListParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemCategoryParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemCategoryParser.java index dcb4cb59f..b677e8b98 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemCategoryParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemCategoryParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemTypeParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemTypeParser.java index edc8eb7d1..f85aca1de 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemTypeParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/ItemTypeParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/MonsterTypeParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/MonsterTypeParser.java index 4f6f47b64..6b50ea74b 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/MonsterTypeParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/MonsterTypeParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/QuestParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/QuestParser.java index 0693e63d8..6316bd6d9 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/QuestParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/QuestParser.java @@ -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 { private final TranslationLoader translationLoader; diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/WorldMapParser.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/WorldMapParser.java index 1e16b09a9..2667fa505 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/WorldMapParser.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/WorldMapParser.java @@ -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 { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/json/JsonCollectionParserFor.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/json/JsonCollectionParserFor.java index 59aeec324..642288c3f 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/json/JsonCollectionParserFor.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/resource/parsers/json/JsonCollectionParserFor.java @@ -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 extends JsonParserFor> { public HashSet parseRows(String input, HashMap dest) { diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/util/Pair.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/util/Pair.java deleted file mode 100644 index 663dc10c7..000000000 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/util/Pair.java +++ /dev/null @@ -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 { - public final T1 first; - public final T2 second; - public Pair(T1 a, T2 b) { - this.first = a; - this.second = b; - } -} diff --git a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/CustomDialogFactory.java b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/CustomDialogFactory.java index fb1de0977..051cae34f 100644 --- a/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/CustomDialogFactory.java +++ b/AndorsTrail/app/src/main/java/com/gpl/rpg/AndorsTrail/view/CustomDialogFactory.java @@ -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); diff --git a/AndorsTrail/res/layout/about.xml b/AndorsTrail/res/layout/about.xml index 3eebd04fa..2ccfefb46 100644 --- a/AndorsTrail/res/layout/about.xml +++ b/AndorsTrail/res/layout/about.xml @@ -5,6 +5,7 @@ android:layout_height="match_parent" android:padding="@dimen/dialog_margin" android:orientation="vertical" + android:id="@+id/about_root" > + android:orientation="vertical" + android:id="@+id/actorconditioninfo_root"> + android:orientation="vertical" android:id="@+id/bulkselection_root"> + android:orientation="vertical" + android:id="@+id/worldmap_root"> + android:orientation="vertical" + android:id="@+id/iteminfo_root"> + android:padding="@dimen/dialog_margin" + android:id="@+id/levelup_root"> + android:orientation="vertical" + android:id="@+id/monsterencounter_root"> + android:orientation="vertical" + android:id="@+id/monsterinfo_root"> + android:orientation="vertical" + android:id="@+id/skillinfo_root"> 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()