diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/GameState.kt b/app/src/main/kotlin/org/carstenf/wordfinder/GameState.kt index 5bb1afc..f6c53f4 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/GameState.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/GameState.kt @@ -11,7 +11,11 @@ import android.util.Log import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import org.carstenf.wordfinder.dictionary.Dictionary +import org.carstenf.wordfinder.letters.LANGUAGE +import org.carstenf.wordfinder.letters.pickRandomLetter import org.carstenf.wordfinder.util.CountUpTimer +import org.carstenf.wordfinder.util.Result +import org.carstenf.wordfinder.util.SolveTask import java.util.Arrays import java.util.Locale @@ -55,7 +59,12 @@ class GameState : ViewModel() { Log.d(WordFinder.TAG, "Letter selector: ${letterRandomDistCur.name}") // NON-NLS for (i in 0..15) { - board[i] = pickRandomLetter(letterRandomDistCur, letterCounts, dictionaryCountryCode(), i).uppercaseChar() + board[i] = pickRandomLetter( + letterRandomDistCur, + letterCounts, + dictionaryCountryCode(), + i + ).uppercaseChar() } board.shuffle() diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/WordFinder.kt b/app/src/main/kotlin/org/carstenf/wordfinder/WordFinder.kt index 42c41d8..5c3e13e 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/WordFinder.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/WordFinder.kt @@ -58,6 +58,7 @@ import org.carstenf.wordfinder.gui.AppCompatLetterButton import org.carstenf.wordfinder.gui.BackGestureBlockingTableLayout import org.carstenf.wordfinder.gui.ComputerResultListAdapter import org.carstenf.wordfinder.gui.drawConnectionsBetweenButtons +import org.carstenf.wordfinder.util.Result import org.carstenf.wordfinder.util.addGestureHandler import org.carstenf.wordfinder.util.isGestureNavigationEnabled import org.carstenf.wordfinder.util.parseTime @@ -654,7 +655,7 @@ class WordFinder : AppCompatActivity(), OnSharedPreferenceChangeListener { private fun insertPlayerResult(guess: Dictionary.WordInfoData) { playerResultList.insert(Result(guess), 0) playerResultList.sort { - object1: Result, object2: Result -> + object1: Result, object2: Result -> val s1 = object1.toString() val s2 = object2.toString() s1.compareTo(s2) diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/WordDefinitionLookupManager.kt b/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/WordDefinitionLookupManager.kt index adffbcb..3e59ada 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/WordDefinitionLookupManager.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/WordDefinitionLookupManager.kt @@ -5,7 +5,7 @@ import android.widget.Toast import androidx.lifecycle.MutableLiveData import org.carstenf.wordfinder.GameState import org.carstenf.wordfinder.R -import org.carstenf.wordfinder.Result +import org.carstenf.wordfinder.util.Result import org.carstenf.wordfinder.WordFinder import org.carstenf.wordfinder.util.isNetworkAvailable import org.carstenf.wordfinder.util.showHyperlinkDialog diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/gui/ComputerResultListAdapter.kt b/app/src/main/kotlin/org/carstenf/wordfinder/gui/ComputerResultListAdapter.kt index b4d79d9..2c63c45 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/gui/ComputerResultListAdapter.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/gui/ComputerResultListAdapter.kt @@ -9,7 +9,7 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.TextView import org.carstenf.wordfinder.R -import org.carstenf.wordfinder.Result +import org.carstenf.wordfinder.util.Result open class ComputerResultListAdapter(context: Context) : ArrayAdapter(context, R.layout.list_item, R.id.resultText) { diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/gui/InfoDialogFragment.kt b/app/src/main/kotlin/org/carstenf/wordfinder/gui/InfoDialogFragment.kt index 0769ed1..4ba2a67 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/gui/InfoDialogFragment.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/gui/InfoDialogFragment.kt @@ -7,7 +7,6 @@ package org.carstenf.wordfinder.gui import android.app.Dialog -import android.content.res.Resources import android.graphics.drawable.Drawable import android.os.Build import android.os.Bundle @@ -23,13 +22,17 @@ import android.widget.TextView import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentManager +import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.ViewPager2 import org.carstenf.wordfinder.BuildConfig import org.carstenf.wordfinder.GameState +import org.carstenf.wordfinder.R import org.carstenf.wordfinder.gui.InfoDialogFragment.Companion.TAG import java.io.InputStream import java.util.Locale +import kotlin.math.min +import android.content.res.Configuration class InfoDialogFragment : DialogFragment() { @@ -44,20 +47,28 @@ class InfoDialogFragment : DialogFragment() { rawText.replace("X.X", BuildConfig.VERSION_NAME) } catch (e: Exception) { Log.e(TAG, e.message,e ) - "Error loading HTML content: ${e.message}" + getString(R.string.error_loading_html_content, e.message) } } private var dialogView : View? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + // Obtain the GameState ViewModel scoped to the hosting Activity + // This ensures the same instance is used across configuration changes + // and is shared with the Activity. + gameState = ViewModelProvider(requireActivity())[GameState::class.java] + } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(requireContext(), android.R.style.Theme_Black_NoTitleBar_Fullscreen) - val lDialogView = requireActivity().layoutInflater.inflate(org.carstenf.wordfinder.R.layout.dialog_info, null) + val lDialogView = requireActivity().layoutInflater.inflate(R.layout.dialog_info, null) builder.setView(lDialogView) - val viewPager: ViewPager2 = lDialogView.findViewById(org.carstenf.wordfinder.R.id.view_pager) - val prevButton: Button = lDialogView.findViewById(org.carstenf.wordfinder.R.id.prev_button) - val nextButton: Button = lDialogView.findViewById(org.carstenf.wordfinder.R.id.next_button) - val closeButton: Button = lDialogView.findViewById(org.carstenf.wordfinder.R.id.close_button) + val viewPager: ViewPager2 = lDialogView.findViewById(R.id.view_pager) + val prevButton: Button = lDialogView.findViewById(R.id.prev_button) + val nextButton: Button = lDialogView.findViewById(R.id.next_button) + val closeButton: Button = lDialogView.findViewById(R.id.close_button) dialogView = lDialogView val locale = Locale.getDefault().language @@ -107,10 +118,6 @@ class InfoDialogFragment : DialogFragment() { override fun onPageSelected(position: Int) { prevButton.isEnabled = position > 0 nextButton.isEnabled = position < pages.size - 1 -// val scrollView = viewPager.findViewById(R.id.info_scrollview) -// scrollView.post { -// scrollView.smoothScrollBy(0, 50) // Subtle nudge down -// } } }) @@ -120,39 +127,59 @@ class InfoDialogFragment : DialogFragment() { override fun onDetach() { super.onDetach() - gameState.onResume() - } - - override fun onResume() { - super.onResume() - val height = (resources.displayMetrics.heightPixels * 0.8).toInt() - val lDialogView = dialogView - if(lDialogView != null) { - lDialogView.layoutParams.height = height - lDialogView.requestLayout() - lDialogView.invalidate() - lDialogView.forceLayout() - lDialogView.bringToFront() + gameState?.onResume() + if(gameState==null) { + Log.e(TAG, "gameState is null in InfoDialogFragment#onDetach") // NON-NLS } } + override fun onStart() { super.onStart() - val height = (resources.displayMetrics.heightPixels * 0.8).toInt() - val lWindow = dialog?.window - if( lWindow !=null ){ - lWindow.setLayout((resources.displayMetrics.widthPixels * 0.95).toInt(), height) - lWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND, WindowManager.LayoutParams.FLAG_DIM_BEHIND) + dialog?.window?.let { window -> + // It's best to get insets on the decorView + val decorView = window.decorView + androidx.core.view.ViewCompat.setOnApplyWindowInsetsListener(decorView) { v, insets -> + val systemBars = insets.getInsets( + androidx.core.view.WindowInsetsCompat.Type.systemBars() or + androidx.core.view.WindowInsetsCompat.Type.displayCutout() + ) + + val displayMetrics = resources.displayMetrics + val availableWidth = displayMetrics.widthPixels - systemBars.left - systemBars.right + val availableHeight = displayMetrics.heightPixels - systemBars.top - systemBars.bottom + + val currentOrientation = resources.configuration.orientation + var dialogWidth = (availableWidth * 0.95).toInt() + + if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) { + dialogWidth = (availableWidth * 0.90).toInt() + } + val dialogHeight = (availableHeight * 0.80).toInt() + + window.setLayout(dialogWidth, dialogHeight) + window.setGravity(android.view.Gravity.CENTER) + window.setFlags( + WindowManager.LayoutParams.FLAG_DIM_BEHIND, + WindowManager.LayoutParams.FLAG_DIM_BEHIND + ) + + // If you only need to apply once, you can remove the listener + // androidx.core.view.ViewCompat.setOnApplyWindowInsetsListener(v, null) + + insets // Return the insets + } + // Request insets to trigger the listener + androidx.core.view.ViewCompat.requestApplyInsets(decorView) } } - private lateinit var gameState: GameState + private var gameState: GameState? = null companion object { const val TAG = "WordFinder InfoDialog" // NON-NLS fun showInfo(fragmentManager: FragmentManager, state: GameState) { val dialogFragment = InfoDialogFragment() - dialogFragment.gameState = state state.onPause() dialogFragment.show(fragmentManager, TAG) } @@ -165,7 +192,7 @@ class InfoPagerAdapter(private val pages: List) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageViewHolder { - val view = LayoutInflater.from(parent.context).inflate(org.carstenf.wordfinder.R.layout.item_info_page, parent, false) + val view = LayoutInflater.from(parent.context).inflate(R.layout.item_info_page, parent, false) return PageViewHolder(view) } @@ -176,7 +203,7 @@ class InfoPagerAdapter(private val pages: List) : override fun getItemCount(): Int = pages.size class PageViewHolder(view: View) : RecyclerView.ViewHolder(view) { - private val textView: TextView = view.findViewById(org.carstenf.wordfinder.R.id.info_text) + private val textView: TextView = view.findViewById(R.id.info_text) fun bind(page: PageData) { // Use the newer Html.fromHtml method with FROM_HTML_MODE_LEGACY @@ -210,11 +237,12 @@ class DialogImageHandler(private val page: PageData, private val textView: TextV val originalWidth = drawable.intrinsicWidth val originalHeight = drawable.intrinsicHeight - val screenWidth = Resources.getSystem().displayMetrics.widthPixels // Get the width of the TextView - var desiredWidth = originalWidth * 4 + val metrics = textView.resources.displayMetrics + val screenWidth = metrics.widthPixels // Get the width of the TextView + val density = metrics.density + val maxWidth = (500 * density).toInt() // Convert dp to px. We want the dialog to be at least 300dp - if(desiredWidth> screenWidth*0.8) - desiredWidth = (screenWidth*0.8).toInt() + val desiredWidth = min ((screenWidth*0.8).toInt(), maxWidth) // Calculate the height to maintain the aspect ratio val desiredHeight = originalHeight * ( desiredWidth*1.0 / originalWidth) diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistribution2D.kt b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistribution2D.kt similarity index 98% rename from app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistribution2D.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistribution2D.kt index 0fa7d3c..453fc5e 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistribution2D.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistribution2D.kt @@ -1,6 +1,4 @@ -package org.carstenf.wordfinder.dictionary - -import org.carstenf.wordfinder.LANGUAGE +package org.carstenf.wordfinder.letters //fun pickRandomLetter2DDistribution(letterCounts: IntArray, languageCode: LANGUAGE) : Char { // return pickRandomLetter2DDistributionF(letterCounts, languageCode) { it } diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDice.kt b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDice.kt similarity index 95% rename from app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDice.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDice.kt index c68ae50..6810214 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDice.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDice.kt @@ -1,6 +1,4 @@ -package org.carstenf.wordfinder.dictionary - -import org.carstenf.wordfinder.LANGUAGE +package org.carstenf.wordfinder.letters fun pickRandomLetterDice(fieldNumber: Int, countryCode: LANGUAGE): Char { val r = Math.random() diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDictionary1D.kt b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDictionary1D.kt similarity index 95% rename from app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDictionary1D.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDictionary1D.kt index c403bf6..52ed429 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/dictionary/LetterDistributionDictionary1D.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterDistributionDictionary1D.kt @@ -1,6 +1,4 @@ -package org.carstenf.wordfinder.dictionary - -import org.carstenf.wordfinder.LANGUAGE +package org.carstenf.wordfinder.letters fun pickRandomLetterDictionary(countryCode: LANGUAGE): Char { val r = Math.random() diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/LetterPicker.kt b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterPicker.kt similarity index 78% rename from app/src/main/kotlin/org/carstenf/wordfinder/LetterPicker.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterPicker.kt index e0dd0ac..e10ffc0 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/LetterPicker.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/letters/LetterPicker.kt @@ -1,8 +1,6 @@ -package org.carstenf.wordfinder +package org.carstenf.wordfinder.letters -import org.carstenf.wordfinder.dictionary.pickRandomLetter2DDistributionF -import org.carstenf.wordfinder.dictionary.pickRandomLetterDice -import org.carstenf.wordfinder.dictionary.pickRandomLetterDictionary +import org.carstenf.wordfinder.GameState import kotlin.math.pow diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/Result.kt b/app/src/main/kotlin/org/carstenf/wordfinder/util/Result.kt similarity index 92% rename from app/src/main/kotlin/org/carstenf/wordfinder/Result.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/util/Result.kt index 3fc1d82..a4ba601 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/Result.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/util/Result.kt @@ -4,7 +4,7 @@ * License: GNU GENERAL PUBLIC LICENSE 3.0 (https://www.gnu.org/copyleft/gpl.html) * */ -package org.carstenf.wordfinder +package org.carstenf.wordfinder.util import org.carstenf.wordfinder.dictionary.Dictionary diff --git a/app/src/main/kotlin/org/carstenf/wordfinder/SolveTask.kt b/app/src/main/kotlin/org/carstenf/wordfinder/util/SolveTask.kt similarity index 90% rename from app/src/main/kotlin/org/carstenf/wordfinder/SolveTask.kt rename to app/src/main/kotlin/org/carstenf/wordfinder/util/SolveTask.kt index 0db983f..37ebd80 100644 --- a/app/src/main/kotlin/org/carstenf/wordfinder/SolveTask.kt +++ b/app/src/main/kotlin/org/carstenf/wordfinder/util/SolveTask.kt @@ -4,7 +4,7 @@ * License: GNU GENERAL PUBLIC LICENSE 3.0 (https://www.gnu.org/copyleft/gpl.html) * */ -package org.carstenf.wordfinder +package org.carstenf.wordfinder.util import android.util.Log import kotlinx.coroutines.CoroutineScope @@ -12,6 +12,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import org.carstenf.wordfinder.GameState +import org.carstenf.wordfinder.WordFinder import org.carstenf.wordfinder.dictionary.Dictionary class SolveTask(private val gameState: GameState) { @@ -54,7 +56,7 @@ class SolveTask(private val gameState: GameState) { prefixes.add(""+prefix[0]+prefix[1]+'U') } } else { - for (next in WordFinder.MOVES[move]) { + for (next in WordFinder.Companion.MOVES[move]) { if (!taken[next]) { findAnyWord(next, taken, depth - 1, res + gameState.getBoard(move), prefixes) } @@ -69,7 +71,7 @@ class SolveTask(private val gameState: GameState) { for (result in resultList) { val minLength = if (gameState.isAllow3LetterWords) 3 else 4 if (result.text.length >= minLength && gameState.findWord(result.text)) { - Log.d(WordFinder.TAG, "Found: $result") // NON-NLS + Log.d(WordFinder.Companion.TAG, "Found: $result") // NON-NLS publishProgress(result) } } diff --git a/app/src/main/res/layout/dialog_info.xml b/app/src/main/res/layout/dialog_info.xml index 4e150b7..53a0f32 100644 --- a/app/src/main/res/layout/dialog_info.xml +++ b/app/src/main/res/layout/dialog_info.xml @@ -4,7 +4,6 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:translationZ="8dp" android:background="@drawable/listview_border" android:padding="8dp"> @@ -14,14 +13,12 @@ android:layout_height="0dp" android:layout_weight="1" android:background="@drawable/listview_border" - android:translationZ="8dp" /> @@ -43,7 +39,6 @@ android:text=">>" android:minWidth="48dp" android:minHeight="48dp" - android:translationZ="8dp" android:background="@drawable/listview_border" tools:ignore="HardcodedText" /> @@ -59,7 +54,6 @@ android:minWidth="48dp" android:minHeight="48dp" android:text="X" - android:translationZ="8dp" android:background="@drawable/listview_border" tools:ignore="HardcodedText" /> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d6dbe98..a4da8f4 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,7 +1,7 @@ Word Finder - Info + Hilfe Einstellungen Einstellungen Würfeln @@ -56,4 +56,5 @@ Disabled Letter Button %1$s Derzeitiges wort ist %1$s Derzeitiges Wort ist leer + Bild konnte nicht geladen werden: %1$s \ No newline at end of file diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 5ecf327..4641249 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -6,7 +6,7 @@ English (US) English (Int.) German (Superdic) - Info + Help Preferences Preferences Shuffle @@ -68,4 +68,5 @@ Disabled Letter Button %1$s Current guess is %1$s Current guess is empty + Error loading HTML content: %1$s diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 639b36d..2d32384 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -6,7 +6,7 @@ English (US) English (Int.) German (Superdic) - Info + Help Preferences Preferences Shuffle @@ -68,4 +68,5 @@ Disabled Letter Button %1$s Current guess is %1$s Current guess is empty + Error loading HTML content: %1$s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 643c5c2..e1f44f1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ Word Finder - Info + Help Preferences Preferences 00:00 @@ -57,4 +57,5 @@ Disabled Letter Button %1$s Current guess is %1$s Current guess is empty + Error loading HTML content: %1$s