Skip to content

Commit a3aee4b

Browse files
feat: Add Spinner lesson and remove Finnish and Lithuanian translations
This commit introduces a new lesson for Spinners, including: - SpinnerActivity and SpinnerCodeActivity. - Layout files for the Spinner lesson and its code tabs. - Java and XML code snippets for the Spinner example. - String resources for Spinner titles, descriptions, and UI elements in multiple languages. - An icon for the Spinner lesson. - Integration into the Android Studio preferences screen and LessonRepository. - Entries in the arrays.xml for Spinner lesson options. Additionally, this commit removes the Finnish (values-fi-rFI) and Lithuanian (values-lt-rLT) translations as they are no longer maintained. The CHANGELOG.md has also been updated.
1 parent c2968b9 commit a3aee4b

File tree

41 files changed

+662
-32
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+662
-32
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Version 5.0.3:
2+
3+
- **New**: A cleaner, more intuitive layout awaits in your app settings.
4+
- **Patch**: Minor visual fixes and UI adjustments.
5+
- **Patch**: General bug fixes for better performance.
6+
17
# Version 5.0.2:
28

39
- **New**: Added a Room database lesson demonstrating entity & DAO.

app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@
128128
android:exported="false"
129129
android:label="@string/web_view"
130130
android:parentActivityName=".ui.screens.main.MainActivity" />
131+
<activity
132+
android:name=".ui.screens.android.lessons.views.spinner.SpinnerActivity"
133+
android:exported="false"
134+
android:label="@string/spinner"
135+
android:parentActivityName=".ui.screens.main.MainActivity" />
136+
<activity
137+
android:name=".ui.screens.android.lessons.views.spinner.SpinnerCodeActivity"
138+
android:exported="false"
139+
android:label="@string/spinner"
140+
android:parentActivityName=".ui.screens.android.lessons.views.spinner.SpinnerActivity" />
131141

132142
<activity-alias
133143
android:name="com.d4rk.androidtutorials.java.ui.android.webviews.WebViewActivity"
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner;
2+
3+
import android.content.Intent;
4+
import android.os.Bundle;
5+
import android.os.Handler;
6+
import android.os.Looper;
7+
import android.view.View;
8+
import android.widget.AdapterView;
9+
import android.widget.ArrayAdapter;
10+
11+
import androidx.annotation.Nullable;
12+
13+
import com.d4rk.androidtutorials.java.R;
14+
import com.d4rk.androidtutorials.java.ads.AdUtils;
15+
import com.d4rk.androidtutorials.java.databinding.ActivitySpinnerBinding;
16+
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
17+
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
18+
19+
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
20+
21+
public class SpinnerActivity extends UpNavigationActivity {
22+
private final Handler handler = new Handler(Looper.getMainLooper());
23+
private ActivitySpinnerBinding binding;
24+
25+
@Override
26+
protected void onCreate(@Nullable Bundle savedInstanceState) {
27+
super.onCreate(savedInstanceState);
28+
29+
binding = ActivitySpinnerBinding.inflate(getLayoutInflater());
30+
setContentView(binding.getRoot());
31+
32+
EdgeToEdgeDelegate.apply(this, binding.container);
33+
34+
binding.descriptionSection.descriptionHeader.getRoot().setText(R.string.description);
35+
binding.layoutPreviewHeader.getRoot().setText(R.string.layout_preview);
36+
binding.descriptionSection.descriptionText.setText(R.string.summary_spinner);
37+
AdUtils.loadBanner(binding.descriptionSection.adView);
38+
39+
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
40+
41+
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
42+
this,
43+
R.array.spinner_lessons_entries,
44+
android.R.layout.simple_spinner_item
45+
);
46+
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
47+
binding.spinnerOptions.setAdapter(adapter);
48+
if (adapter.getCount() > 0) {
49+
CharSequence firstItem = adapter.getItem(0);
50+
if (firstItem != null) {
51+
binding.textSelectedItem.setText(getString(R.string.spinner_selected_format, firstItem));
52+
}
53+
}
54+
binding.spinnerOptions.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
55+
@Override
56+
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
57+
CharSequence item = (CharSequence) parent.getItemAtPosition(position);
58+
binding.textSelectedItem.setText(getString(R.string.spinner_selected_format, item));
59+
}
60+
61+
@Override
62+
public void onNothingSelected(AdapterView<?> parent) {
63+
binding.textSelectedItem.setText(R.string.spinner_selected_none);
64+
}
65+
});
66+
67+
binding.floatingButtonShowSyntax.setOnClickListener(v ->
68+
startActivity(new Intent(this, SpinnerCodeActivity.class)));
69+
handler.postDelayed(() -> binding.floatingButtonShowSyntax.shrink(), 5000);
70+
}
71+
72+
@Override
73+
protected void onDestroy() {
74+
super.onDestroy();
75+
handler.removeCallbacksAndMessages(null);
76+
}
77+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner;
2+
3+
import android.os.Bundle;
4+
5+
import androidx.annotation.NonNull;
6+
import androidx.annotation.Nullable;
7+
import androidx.fragment.app.Fragment;
8+
import androidx.viewpager2.adapter.FragmentStateAdapter;
9+
10+
import com.d4rk.androidtutorials.java.R;
11+
import com.d4rk.androidtutorials.java.databinding.ActivityTabLayoutBinding;
12+
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
13+
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner.tabs.SpinnerTabCodeFragment;
14+
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner.tabs.SpinnerTabLayoutFragment;
15+
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
16+
import com.google.android.material.tabs.TabLayoutMediator;
17+
18+
import java.util.ArrayList;
19+
20+
public class SpinnerCodeActivity extends UpNavigationActivity {
21+
private ActivityTabLayoutBinding binding;
22+
23+
@Override
24+
protected void onCreate(@Nullable Bundle savedInstanceState) {
25+
super.onCreate(savedInstanceState);
26+
27+
binding = ActivityTabLayoutBinding.inflate(getLayoutInflater());
28+
setContentView(binding.getRoot());
29+
30+
EdgeToEdgeDelegate.apply(this, binding.tabLayout);
31+
32+
setupViewPager();
33+
34+
new TabLayoutMediator(binding.tabs, binding.viewpager, (tab, position) -> {
35+
ViewPagerAdapter adapter = (ViewPagerAdapter) binding.viewpager.getAdapter();
36+
if (adapter != null) {
37+
tab.setText(adapter.getPageTitle(position));
38+
}
39+
}).attach();
40+
}
41+
42+
private void setupViewPager() {
43+
ViewPagerAdapter adapter = new ViewPagerAdapter(this);
44+
adapter.addFragment(new SpinnerTabCodeFragment(), getString(R.string.code_java));
45+
adapter.addFragment(new SpinnerTabLayoutFragment(), getString(R.string.layout_xml));
46+
binding.viewpager.setAdapter(adapter);
47+
}
48+
49+
private static class ViewPagerAdapter extends FragmentStateAdapter {
50+
private final ArrayList<Fragment> fragmentList = new ArrayList<>();
51+
private final ArrayList<String> fragmentTitleList = new ArrayList<>();
52+
53+
public ViewPagerAdapter(@NonNull UpNavigationActivity activity) {
54+
super(activity);
55+
}
56+
57+
public void addFragment(@NonNull Fragment fragment, @NonNull String title) {
58+
fragmentList.add(fragment);
59+
fragmentTitleList.add(title);
60+
}
61+
62+
@NonNull
63+
@Override
64+
public Fragment createFragment(int position) {
65+
return fragmentList.get(position);
66+
}
67+
68+
@Override
69+
public int getItemCount() {
70+
return fragmentList.size();
71+
}
72+
73+
public CharSequence getPageTitle(int position) {
74+
return fragmentTitleList.get(position);
75+
}
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner.tabs;
2+
3+
import android.content.SharedPreferences;
4+
import android.graphics.Typeface;
5+
import android.os.Bundle;
6+
import android.util.Log;
7+
import android.view.LayoutInflater;
8+
import android.view.ViewGroup;
9+
10+
import androidx.annotation.NonNull;
11+
import androidx.preference.PreferenceManager;
12+
13+
import com.d4rk.androidtutorials.java.R;
14+
import com.d4rk.androidtutorials.java.databinding.FragmentCodeBinding;
15+
import com.d4rk.androidtutorials.java.ui.components.NoCodeAdFragment;
16+
import com.d4rk.androidtutorials.java.utils.CodeHighlighter;
17+
import com.d4rk.androidtutorials.java.utils.CodeViewUtils;
18+
import com.d4rk.androidtutorials.java.utils.FontManager;
19+
20+
import java.io.BufferedReader;
21+
import java.io.IOException;
22+
import java.io.InputStream;
23+
import java.io.InputStreamReader;
24+
25+
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
26+
27+
public class SpinnerTabCodeFragment extends NoCodeAdFragment<FragmentCodeBinding> {
28+
29+
@Override
30+
@NonNull
31+
protected FragmentCodeBinding inflateBinding(@NonNull LayoutInflater inflater, ViewGroup container) {
32+
return FragmentCodeBinding.inflate(inflater, container, false);
33+
}
34+
35+
@Override
36+
protected void onBindingCreated(@NonNull FragmentCodeBinding binding, Bundle savedInstanceState) {
37+
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
38+
39+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
40+
Typeface monospaceFont = FontManager.getMonospaceFont(requireContext(), prefs);
41+
CodeViewUtils.applyDefaults(monospaceFont, binding.codeView);
42+
43+
StringBuilder builder = new StringBuilder();
44+
InputStream inputStream = getResources().openRawResource(R.raw.text_spinner_java);
45+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
46+
String line;
47+
while ((line = reader.readLine()) != null) {
48+
builder.append(line).append('\n');
49+
}
50+
binding.codeView.setText(builder.toString());
51+
CodeHighlighter.applyJavaTheme(binding.codeView);
52+
} catch (IOException e) {
53+
Log.e("SpinnerTabCode", "Error reading spinner code", e);
54+
}
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.views.spinner.tabs;
2+
3+
import android.content.SharedPreferences;
4+
import android.graphics.Typeface;
5+
import android.os.Bundle;
6+
import android.util.Log;
7+
import android.view.LayoutInflater;
8+
import android.view.View;
9+
import android.view.ViewGroup;
10+
11+
import androidx.annotation.NonNull;
12+
import androidx.fragment.app.Fragment;
13+
import androidx.preference.PreferenceManager;
14+
15+
import com.d4rk.androidtutorials.java.R;
16+
import com.d4rk.androidtutorials.java.ads.AdUtils;
17+
import com.d4rk.androidtutorials.java.databinding.FragmentLayoutBinding;
18+
import com.d4rk.androidtutorials.java.utils.CodeHighlighter;
19+
import com.d4rk.androidtutorials.java.utils.CodeViewUtils;
20+
import com.d4rk.androidtutorials.java.utils.FontManager;
21+
22+
import java.io.BufferedReader;
23+
import java.io.IOException;
24+
import java.io.InputStream;
25+
import java.io.InputStreamReader;
26+
27+
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
28+
29+
public class SpinnerTabLayoutFragment extends Fragment {
30+
31+
@Override
32+
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
33+
FragmentLayoutBinding binding = FragmentLayoutBinding.inflate(inflater, container, false);
34+
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
35+
AdUtils.loadBanner(binding.adView);
36+
37+
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
38+
Typeface monospaceFont = FontManager.getMonospaceFont(requireContext(), prefs);
39+
CodeViewUtils.applyDefaults(monospaceFont, binding.codeView);
40+
41+
StringBuilder builder = new StringBuilder();
42+
InputStream inputStream = getResources().openRawResource(R.raw.text_spinner_xml);
43+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
44+
String line;
45+
while ((line = reader.readLine()) != null) {
46+
builder.append(line).append('\n');
47+
}
48+
binding.codeView.setText(builder.toString());
49+
CodeHighlighter.applyXmlTheme(binding.codeView);
50+
} catch (IOException e) {
51+
Log.e("SpinnerTabLayout", "Error reading spinner layout", e);
52+
}
53+
return binding.getRoot();
54+
}
55+
}

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/android/repository/LessonRepository.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson ge
3838
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.grid_view, R.raw.text_grid_view_java, R.raw.text_grid_view_xml);
3939
case "WebView" ->
4040
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.web_view, R.raw.text_webview_java, R.raw.text_webview_xml);
41+
case "Spinner" ->
42+
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.spinner, R.raw.text_spinner_java, R.raw.text_spinner_xml);
4143
case "Retrofit" ->
4244
new com.d4rk.androidtutorials.java.data.repository.LessonRepository.Lesson(R.string.retrofit, R.raw.text_retrofit_java, R.raw.text_retrofit_xml);
4345
case "BottomNavigation" ->
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="?attr/colorSecondary"
8+
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm0,12l-4,-4h8l-4,4z" />
9+
</vector>

0 commit comments

Comments
 (0)