Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- **Minor**: Added a search function for lessons.
- **Patch**: Optimized app performance for smoother operation.
- **Patch**: Updated several components to improve compatibility.
- **New**: Added a Room database lesson demonstrating entity, DAO, and code viewer integration.

# Version 5.0.1:

Expand Down
2 changes: 2 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ dependencies {
implementation libs.codeview
implementation libs.hilt.android
annotationProcessor libs.hilt.compiler
implementation libs.androidx.room.runtime
annotationProcessor libs.androidx.room.compiler

// Testing
testImplementation libs.junit
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,18 @@
android:label="@string/navigation_drawer"
android:parentActivityName=".ui.screens.main.MainActivity" />

<activity
android:name=".ui.screens.android.lessons.data.room.RoomActivity"
android:exported="false"
android:label="@string/room_database"
android:parentActivityName=".ui.screens.main.MainActivity" />

<activity
android:name=".ui.screens.android.lessons.data.room.RoomCodeActivity"
android:exported="false"
android:label="@string/room_database"
android:parentActivityName=".ui.screens.android.lessons.data.room.RoomActivity" />

<activity
android:name=".ui.screens.settings.SettingsActivity"
android:exported="false"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room;

import android.content.Context;

import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;

/**
* The Room database that holds the notes.
*/
@Database(entities = {Note.class}, version = 1, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
private static volatile AppDatabase INSTANCE;

public abstract NoteDao noteDao();

public static AppDatabase getInstance(Context context) {
if (INSTANCE == null) {
synchronized (AppDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
AppDatabase.class, "notes_db").build();
}
}
}
return INSTANCE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room;

import androidx.room.Entity;
import androidx.room.PrimaryKey;

/**
* Simple Note entity stored in the Room database.
*/
@Entity(tableName = "notes")
public class Note {
@PrimaryKey(autoGenerate = true)
public int id;
public String text;

public Note(String text) {
this.text = text;
}

public String getText() {
return text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room;

import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;

import java.util.List;

/**
* Data Access Object for {@link Note}.
*/
@Dao
public interface NoteDao {
@Insert
void insert(Note note);

@Query("SELECT * FROM notes")
List<Note> getAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.ActivityRoomBinding;
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
import com.google.android.material.textview.MaterialTextView;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* Demonstrates basic Room usage by inserting and reading notes.
*/
public class RoomActivity extends UpNavigationActivity {
private final Handler handler = new Handler();
private ActivityRoomBinding binding;
private NotesAdapter adapter;
private AppDatabase db;
private final ExecutorService executor = Executors.newSingleThreadExecutor();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityRoomBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdgeDelegate edgeToEdgeDelegate = new EdgeToEdgeDelegate(this);
edgeToEdgeDelegate.applyEdgeToEdge(binding.constraintLayout);

db = AppDatabase.getInstance(this);

binding.recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new NotesAdapter();
binding.recyclerView.setAdapter(adapter);

loadNotes();

binding.buttonAdd.setOnClickListener(v -> {
String text = String.valueOf(binding.editTextNote.getText()).trim();
if (!text.isEmpty()) {
executor.execute(() -> {
db.noteDao().insert(new Note(text));
runOnUiThread(() -> {
binding.editTextNote.setText("");
loadNotes();
});
});
}
});

binding.floatingButtonShowSyntax.setOnClickListener(v ->
startActivity(new Intent(RoomActivity.this, RoomCodeActivity.class)));
handler.postDelayed(() -> binding.floatingButtonShowSyntax.shrink(), 5000);
}

private void loadNotes() {
executor.execute(() -> {
List<Note> notes = db.noteDao().getAll();
runOnUiThread(() -> adapter.setNotes(notes));
});
}

private static class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NoteViewHolder> {
private List<Note> notes = new ArrayList<>();

void setNotes(List<Note> notes) {
this.notes = notes;
notifyDataSetChanged();
}

@NonNull
@Override
public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_note, parent, false);
return new NoteViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull NoteViewHolder holder, int position) {
holder.textView.setText(notes.get(position).getText());
}

@Override
public int getItemCount() {
return notes.size();
}

static class NoteViewHolder extends RecyclerView.ViewHolder {
final MaterialTextView textView;

NoteViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.textViewNote);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room;

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.ActivityTabLayoutBinding;
import com.d4rk.androidtutorials.java.ui.components.navigation.UpNavigationActivity;
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room.tabs.RoomTabCodeFragment;
import com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room.tabs.RoomTabLayoutFragment;
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
import com.google.android.material.tabs.TabLayoutMediator;

import java.util.ArrayList;

/**
* Displays Java and XML snippets for the Room database example.
*/
public class RoomCodeActivity extends UpNavigationActivity {
private ActivityTabLayoutBinding binding;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityTabLayoutBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

EdgeToEdgeDelegate edgeToEdgeDelegate = new EdgeToEdgeDelegate(this);
edgeToEdgeDelegate.applyEdgeToEdge(binding.appBarLayout);

setupViewPager();

new TabLayoutMediator(binding.tabs, binding.viewpager, (tab, position) -> {
ViewPagerAdapter adapter = (ViewPagerAdapter) binding.viewpager.getAdapter();
if (adapter != null) {
tab.setText(adapter.getPageTitle(position));
}
}).attach();
}

private void setupViewPager() {
ViewPagerAdapter adapter = new ViewPagerAdapter(this);
adapter.addFragment(new RoomTabCodeFragment(), getString(R.string.code_java));
adapter.addFragment(new RoomTabLayoutFragment(), getString(R.string.layout_xml));
binding.viewpager.setAdapter(adapter);
}

private static class ViewPagerAdapter extends FragmentStateAdapter {
private final ArrayList<Fragment> fragmentList = new ArrayList<>();
private final ArrayList<String> fragmentTitleList = new ArrayList<>();

ViewPagerAdapter(@NonNull UpNavigationActivity activity) {
super(activity);
}

void addFragment(@NonNull Fragment fragment, @NonNull String title) {
fragmentList.add(fragment);
fragmentTitleList.add(title);
}

@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}

@Override
public int getItemCount() {
return fragmentList.size();
}

CharSequence getPageTitle(int position) {
return fragmentTitleList.get(position);
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.d4rk.androidtutorials.java.ui.screens.android.lessons.data.room.tabs;

import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager;

import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.FragmentCodeBinding;
import com.d4rk.androidtutorials.java.utils.CodeHighlighter;
import com.d4rk.androidtutorials.java.utils.CodeViewUtils;
import com.d4rk.androidtutorials.java.utils.FontManager;
import com.google.android.gms.ads.AdRequest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import me.zhanghai.android.fastscroll.FastScrollerBuilder;

/**
* Shows the Java implementation for the Room example.
*/
public class RoomTabCodeFragment extends Fragment {

@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
FragmentCodeBinding binding = FragmentCodeBinding.inflate(inflater, container, false);
new FastScrollerBuilder(binding.scrollView).useMd2Style().build();
binding.adView.loadAd(new AdRequest.Builder().build());

SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(requireContext());
Typeface monospaceFont = FontManager.getMonospaceFont(requireContext(), prefs);
CodeViewUtils.applyDefaults(monospaceFont, binding.codeView);

StringBuilder builder = new StringBuilder();
InputStream inputStream = getResources().openRawResource(R.raw.text_room_java);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append('\n');
}
binding.codeView.setText(builder.toString());
CodeHighlighter.applyJavaTheme(binding.codeView);
} catch (IOException e) {
Log.e("RoomTabCode", "Error reading code", e);
}
return binding.getRoot();
}
}

Loading