create stub chat fragment

This commit is contained in:
Daniel Gultsch 2023-03-21 11:03:50 +01:00
parent 0f6f9b0001
commit 86d9264ee5
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
20 changed files with 333 additions and 7 deletions

View file

@ -1,23 +1,22 @@
package im.conversations.android.ui; package im.conversations.android.ui;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build; import android.os.Build;
import android.view.View; import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.elevation.SurfaceColors; import com.google.android.material.elevation.SurfaceColors;
public final class Activities { public final class Activities {
private Activities() {} private Activities() {}
public static void setStatusAndNavigationBarColors( public static void setStatusAndNavigationBarColors(final Activity activity, final View view) {
final AppCompatActivity activity, final View view) {
setStatusAndNavigationBarColors(activity, view, false); setStatusAndNavigationBarColors(activity, view, false);
} }
public static void setStatusAndNavigationBarColors( public static void setStatusAndNavigationBarColors(
final AppCompatActivity activity, final View view, final boolean raisedStatusBar) { final Activity activity, final View view, final boolean raisedStatusBar) {
final var isLightMode = isLightMode(activity); final var isLightMode = isLightMode(activity);
final var window = activity.getWindow(); final var window = activity.getWindow();
final var flags = view.getSystemUiVisibility(); final var flags = view.getSystemUiVisibility();

View file

@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModelProvider;
import im.conversations.android.R; import im.conversations.android.R;
import im.conversations.android.databinding.ActivityMainBinding; import im.conversations.android.databinding.ActivityMainBinding;
import im.conversations.android.service.ForegroundService; import im.conversations.android.service.ForegroundService;
import im.conversations.android.ui.Activities;
import im.conversations.android.ui.model.MainViewModel; import im.conversations.android.ui.model.MainViewModel;
public class MainActivity extends BaseActivity { public class MainActivity extends BaseActivity {
@ -30,7 +29,6 @@ public class MainActivity extends BaseActivity {
finish(); finish();
} }
}); });
Activities.setStatusAndNavigationBarColors(this, binding.getRoot());
} }
@Override @Override

View file

@ -12,6 +12,7 @@ import im.conversations.android.R;
import im.conversations.android.database.model.ChatOverviewItem; import im.conversations.android.database.model.ChatOverviewItem;
import im.conversations.android.databinding.ItemChatoverviewBinding; import im.conversations.android.databinding.ItemChatoverviewBinding;
import im.conversations.android.ui.AvatarFetcher; import im.conversations.android.ui.AvatarFetcher;
import java.util.function.Consumer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -20,6 +21,8 @@ public class ChatOverviewAdapter
private static final Logger LOGGER = LoggerFactory.getLogger(ChatOverviewAdapter.class); private static final Logger LOGGER = LoggerFactory.getLogger(ChatOverviewAdapter.class);
private Consumer<Long> onChatSelected;
public ChatOverviewAdapter(@NonNull DiffUtil.ItemCallback<ChatOverviewItem> diffCallback) { public ChatOverviewAdapter(@NonNull DiffUtil.ItemCallback<ChatOverviewItem> diffCallback) {
super(diffCallback); super(diffCallback);
} }
@ -42,6 +45,12 @@ public class ChatOverviewAdapter
final var addressWithName = final var addressWithName =
chatOverviewItem == null ? null : chatOverviewItem.getAddressWithName(); chatOverviewItem == null ? null : chatOverviewItem.getAddressWithName();
final var avatar = chatOverviewItem == null ? null : chatOverviewItem.getAvatar(); final var avatar = chatOverviewItem == null ? null : chatOverviewItem.getAvatar();
holder.binding.chat.setOnClickListener(
(v) -> {
if (onChatSelected != null && chatOverviewItem != null) {
onChatSelected.accept(chatOverviewItem.id);
}
});
if (avatar != null) { if (avatar != null) {
holder.binding.avatar.setVisibility(View.VISIBLE); holder.binding.avatar.setVisibility(View.VISIBLE);
AvatarFetcher.fetchInto(holder.binding.avatar, avatar); AvatarFetcher.fetchInto(holder.binding.avatar, avatar);
@ -53,6 +62,10 @@ public class ChatOverviewAdapter
} }
} }
public void setOnChatSelectedListener(final Consumer<Long> onChatSelected) {
this.onChatSelected = onChatSelected;
}
public static class ChatOverviewViewHolder extends RecyclerView.ViewHolder { public static class ChatOverviewViewHolder extends RecyclerView.ViewHolder {
private final ItemChatoverviewBinding binding; private final ItemChatoverviewBinding binding;

View file

@ -0,0 +1,40 @@
package im.conversations.android.ui.fragment.main;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import im.conversations.android.R;
import im.conversations.android.databinding.FragmentChatBinding;
import im.conversations.android.ui.Activities;
import im.conversations.android.ui.NavControllers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ChatFragment extends Fragment {
private static final Logger LOGGER = LoggerFactory.getLogger(ChatFragment.class);
private FragmentChatBinding binding;
@Override
public View onCreateView(
@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
this.binding = DataBindingUtil.inflate(inflater, R.layout.fragment_chat, container, false);
this.binding.materialToolbar.setNavigationOnClickListener(
view -> {
NavControllers.findNavController(requireActivity(), R.id.nav_host_fragment)
.popBackStack();
});
this.binding.messageLayout.setEndIconOnClickListener(
v -> {
LOGGER.info("On send pressed");
});
Activities.setStatusAndNavigationBarColors(requireActivity(), binding.getRoot(), true);
return this.binding.getRoot();
}
}

View file

@ -23,7 +23,9 @@ import im.conversations.android.database.model.AccountIdentifier;
import im.conversations.android.database.model.ChatFilter; import im.conversations.android.database.model.ChatFilter;
import im.conversations.android.database.model.GroupIdentifier; import im.conversations.android.database.model.GroupIdentifier;
import im.conversations.android.databinding.FragmentOverviewBinding; import im.conversations.android.databinding.FragmentOverviewBinding;
import im.conversations.android.ui.Activities;
import im.conversations.android.ui.Intents; import im.conversations.android.ui.Intents;
import im.conversations.android.ui.NavControllers;
import im.conversations.android.ui.activity.SettingsActivity; import im.conversations.android.ui.activity.SettingsActivity;
import im.conversations.android.ui.activity.SetupActivity; import im.conversations.android.ui.activity.SetupActivity;
import im.conversations.android.ui.adapter.ChatOverviewAdapter; import im.conversations.android.ui.adapter.ChatOverviewAdapter;
@ -112,9 +114,17 @@ public class OverviewFragment extends Fragment {
requireActivity() requireActivity()
.getOnBackPressedDispatcher() .getOnBackPressedDispatcher()
.addCallback(getViewLifecycleOwner(), this.searchViewOnBackPressedCallback); .addCallback(getViewLifecycleOwner(), this.searchViewOnBackPressedCallback);
this.chatOverviewAdapter.setOnChatSelectedListener(this::onChatSelected);
Activities.setStatusAndNavigationBarColors(requireActivity(), binding.getRoot());
return binding.getRoot(); return binding.getRoot();
} }
private void onChatSelected(long chatId) {
final var navController =
NavControllers.findNavController(requireActivity(), R.id.nav_host_fragment);
navController.navigate(OverviewFragmentDirections.overviewToChat(chatId));
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
@ -238,4 +248,16 @@ public class OverviewFragment extends Fragment {
} }
} }
} }
@Override
public void onDestroyView() {
nullReferences();
super.onDestroyView();
}
private void nullReferences() {
this.binding.chats.setAdapter(null);
this.chatOverviewAdapter = null;
this.binding = null;
}
} }

View file

@ -0,0 +1,3 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="?attr/hintAlpha" android:color="?colorOnTertiaryContainer" />
</selector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M13,7h-2v4L7,11v2h4v4h2v-4h4v-2h-4L13,7zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z" />
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z" />
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M787.17,456.04Q782.17,335.04 697.67,250.54Q613.17,166.04 492.17,161.04L492.17,94.82Q566.3,96.82 631.22,125.89Q696.13,154.96 744.7,203.52Q793.26,252.09 822.33,317Q851.39,381.91 853.39,456.04L787.17,456.04ZM610.39,456.04Q605.39,408.87 572.37,376.07Q539.35,343.26 492.17,338.26L492.17,272.04Q567.17,277.04 619.67,329.04Q672.17,381.04 677.17,456.04L610.39,456.04ZM795.57,853Q670.74,853 547.7,791.87Q424.65,730.74 326.39,632.76Q228.13,534.78 167,411.46Q105.87,288.13 105.87,163.87Q105.87,139.22 122.83,122.26Q139.78,105.3 164.43,105.3L304.43,105.3Q328.04,105.3 343.63,118.48Q359.22,131.65 364.48,156.13L391.48,273.09Q395.17,294.43 390.7,310.46Q386.22,326.48 373.7,337.87L270.87,435.48Q323.48,520.57 386.76,583.07Q450.04,645.57 529,689.04L626.83,589.35Q641.35,574.39 658.59,568.76Q675.83,563.13 695.61,567.83L802.74,592.69Q826.78,598.52 840.46,615.04Q854.13,631.57 854.13,656.04L854.13,793.87Q854.13,819.09 837.17,836.04Q820.22,853 795.57,853Z" />
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4zM14,13h-3v3H9v-3H6v-2h3V8h2v3h3v2z" />
</vector>

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2019 Daniel Gultsch
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="4dp"
app:liftOnScroll="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_arrow_back_24dp"
app:menu="@menu/fragment_chat"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/chat"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/chats"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/message_layout"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:layout_marginStart="8dp"
android:id="@+id/add_content"
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/ic_add_circle_outline_24dp"
app:iconTint="?colorOnSurface"
app:iconSize="24dp"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="@+id/message_layout"
app:layout_constraintEnd_toStartOf="@+id/message_layout"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/message_layout"
style="@style/Widget.Material3.TextInputLayout.FilledBox"
android:theme="@style/ThemeOverlay.C3.TextSelection.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:minHeight="48dp"
app:boxBackgroundColor="?colorTertiaryContainer"
app:boxCornerRadiusBottomEnd="24dp"
app:boxCornerRadiusBottomStart="24dp"
app:boxCornerRadiusTopEnd="24dp"
app:boxCornerRadiusTopStart="24dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:endIconDrawable="@drawable/ic_send_24dp"
app:endIconMode="custom"
app:endIconTint="?colorOnTertiaryContainer"
app:expandedHintEnabled="false"
app:helperTextEnabled="false"
app:hintEnabled="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/add_content">
<com.google.android.material.textfield.TextInputEditText
style="@style/Widget.C3.TextInputEditText.FilledBox.Tertiary"
android:theme="@style/ThemeOverlay.C3.TextSelection.Secondary"
android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/send_message"
android:padding="8dp"
android:maxHeight="112dp" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

View file

@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/chat"
android:foreground="?android:attr/selectableItemBackground"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="72dp" android:layout_height="72dp"
app:layout_constraintBottom_toBottomOf="@+id/name" app:layout_constraintBottom_toBottomOf="@+id/name"

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_ongoing_call"
android:icon="@drawable/ic_phone_in_talk_24dp"
android:orderInCategory="9"
android:title="@string/return_to_ongoing_call"
android:visible="false"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_call"
android:icon="@drawable/ic_call_24dp"
android:orderInCategory="10"
android:title="@string/make_call"
app:showAsAction="ifRoom">
<menu>
<item
android:id="@+id/action_audio_call"
android:icon="@drawable/ic_call_24dp"
android:title="@string/audio_call" />
<item
android:id="@+id/action_video_call"
android:icon="@drawable/ic_video_call_24dp"
android:title="@string/video_call" />
</menu>
</item>
<item
android:id="@+id/action_security"
android:icon="@drawable/ic_lock_open_24dp"
android:orderInCategory="20"
android:title="@string/encrypted_with_omemo"
app:showAsAction="ifRoom">
<menu>
<group android:checkableBehavior="single">
<item
android:id="@+id/encryption_choice_none"
android:title="@string/encryption_choice_unencrypted" />
<item
android:id="@+id/encryption_choice_axolotl"
android:title="@string/encryption_choice_omemo" />
<item
android:id="@+id/encryption_choice_pgp"
android:title="@string/encryption_choice_pgp" />
</group>
</menu>
</item>
<item
android:orderInCategory="70"
android:id="@+id/archive_chat"
android:title="@string/archive"
app:showAsAction="never" />
<item
android:orderInCategory="80"
android:id="@+id/delete"
android:title="@string/delete"
app:showAsAction="never" />
</menu>

View file

@ -22,7 +22,17 @@
<fragment <fragment
android:id="@+id/overview" android:id="@+id/overview"
android:name="im.conversations.android.ui.fragment.main.OverviewFragment" android:name="im.conversations.android.ui.fragment.main.OverviewFragment"
tools:layout="@layout/fragment_overview" /> tools:layout="@layout/fragment_overview">
<action android:id="@+id/overview_to_chat" app:destination="@+id/chat"/>
</fragment>
<fragment android:id="@+id/chat"
android:name="im.conversations.android.ui.fragment.main.ChatFragment"
tools:layout="@layout/fragment_chat">
<argument android:name="chat"
app:argType="long"
app:nullable="false"/>
</fragment>
</navigation> </navigation>

View file

@ -27,5 +27,6 @@
<item name="colorOnSurfaceInverse">@color/md_theme_dark_inverseOnSurface</item> <item name="colorOnSurfaceInverse">@color/md_theme_dark_inverseOnSurface</item>
<item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item> <item name="colorSurfaceInverse">@color/md_theme_dark_inverseSurface</item>
<item name="colorPrimaryInverse">@color/md_theme_dark_inversePrimary</item> <item name="colorPrimaryInverse">@color/md_theme_dark_inversePrimary</item>
<item name="hintAlpha">0.5</item>
</style> </style>
</resources> </resources>

View file

@ -0,0 +1,5 @@
<resources>
<declare-styleable name="C3">
<attr name="hintAlpha" format="float" />
</declare-styleable>
</resources>

View file

@ -1048,5 +1048,6 @@
<string name="trust_cerficate">Trust certificate</string> <string name="trust_cerficate">Trust certificate</string>
<string name="you">You</string> <string name="you">You</string>
<string name="check_your_internet_connection">Check your Internet connection</string> <string name="check_your_internet_connection">Check your Internet connection</string>
<string name="archive">Archive</string>
</resources> </resources>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.C3.TextInputEditText.FilledBox.Tertiary" parent="Widget.Material3.TextInputEditText.FilledBox">
<item name="android:textColor">?colorOnTertiaryContainer</item>
<item name="android:textColorHint">@color/hint_on_tertiary_container</item>
</style>
<style name="ThemeOverlay.C3.TextSelection.Secondary" parent="">
<item name="colorControlActivated">?colorSecondary</item>
<item name="android:textColorHighlight">?colorSecondaryContainer</item>
</style>
</resources>

View file

@ -27,5 +27,6 @@
<item name="colorOnSurfaceInverse">@color/md_theme_light_inverseOnSurface</item> <item name="colorOnSurfaceInverse">@color/md_theme_light_inverseOnSurface</item>
<item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item> <item name="colorSurfaceInverse">@color/md_theme_light_inverseSurface</item>
<item name="colorPrimaryInverse">@color/md_theme_light_inversePrimary</item> <item name="colorPrimaryInverse">@color/md_theme_light_inversePrimary</item>
<item name="hintAlpha">0.5</item>
</style> </style>
</resources> </resources>