android view and stuff

This commit is contained in:
Mike Schwörer 2018-09-22 03:06:09 +02:00
parent 5fcd33e294
commit b6252a1c1a
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
14 changed files with 403 additions and 77 deletions

View File

@ -21,7 +21,9 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.google.firebase:firebase-core:16.0.3'
implementation 'com.google.firebase:firebase-messaging:17.3.2'

View File

@ -4,6 +4,7 @@
<application
android:allowBackup="false"
android:name="SCNApp"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"

View File

@ -0,0 +1,35 @@
package com.blackforestbytes.simplecloudnotifier;
import android.annotation.SuppressLint;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class CMessage
{
public final long Timestamp ;
public final String Title;
public final String Content;
private static final SimpleDateFormat _format;
static
{
_format = new SimpleDateFormat("yyyy'-'MM'-'dd HH':'mm':'ss", Locale.getDefault());
_format.setTimeZone(TimeZone.getDefault());
}
public CMessage(long t, String mt, String mc)
{
Timestamp = t;
Title = mt;
Content = mc;
}
@SuppressLint("SimpleDateFormat")
public String formatTimestamp()
{
return _format.format(new Date(Timestamp*1000));
}
}

View File

@ -0,0 +1,122 @@
package com.blackforestbytes.simplecloudnotifier;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
public class CMessageList
{
public ArrayList<CMessage> Messages;
private ArrayList<WeakReference<MessageAdapter>> _listener = new ArrayList<>();
private final static Object _lock = new Object();
private static CMessageList _inst = null;
public static CMessageList inst()
{
synchronized (_lock)
{
if (_inst != null) return _inst;
return _inst = new CMessageList();
}
}
private CMessageList()
{
Messages = new ArrayList<>();
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
int count = sharedPref.getInt("message_count", 0);
for (int i=0; i < count; i++)
{
long time = sharedPref.getLong("message["+i+"].timestamp", 0);
String title = sharedPref.getString("message["+i+"].title", "");
String content = sharedPref.getString("message["+i+"].content", "");
Messages.add(new CMessage(time, title, content));
}
}
public void add(final long time, final String title, final String content)
{
boolean run = SCNApp.runOnUiThread(new Runnable() {
@Override
public void run()
{
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
int count = sharedPref.getInt("message_count", 0);
SharedPreferences.Editor e = sharedPref.edit();
Messages.add(new CMessage(time, title, content));
e.putInt("message_count", count+1);
e.putLong("message["+count+"].timestamp", time);
e.putString("message["+count+"].title", title);
e.putString("message["+count+"].content", content);
e.apply();
for (WeakReference<MessageAdapter> ref : _listener)
{
MessageAdapter a = ref.get();
if (a == null) continue;
a.notifyItemInserted(count);
}
CleanUpListener();
}
});
if (!run)
{
Messages.add(new CMessage(time, title, content));
fullSave();
}
}
public void fullSave()
{
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("CMessageList", Context.MODE_PRIVATE);
SharedPreferences.Editor e = sharedPref.edit();
e.clear();
e.putInt("message_count", Messages.size());
for (int i = 0; i < Messages.size(); i++)
{
e.putLong("message["+i+"].timestamp", Messages.get(i).Timestamp);
e.putString("message["+i+"].title", Messages.get(i).Title);
e.putString("message["+i+"].content", Messages.get(i).Content);
}
e.apply();
}
public CMessage tryGet(int pos)
{
if (pos < 0 || pos >= Messages.size()) return null;
return Messages.get(pos);
}
public int size()
{
return Messages.size();
}
public void register(MessageAdapter adp)
{
_listener.add(new WeakReference<>(adp));
CleanUpListener();
}
private void CleanUpListener()
{
for (int i=_listener.size()-1; i >= 0; i--)
{
if (_listener.get(i).get() == null) _listener.remove(i);
}
}
}

View File

@ -1,17 +1,13 @@
package com.blackforestbytes.simplecloudnotifier;
import android.util.Log;
import android.widget.Toast;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class FBMService extends FirebaseMessagingService
{
/**
* Called if InstanceID token is updated. This may occur if the security of
* the previous token had been compromised. Note that this is called when the InstanceID token
* is initially generated so this is where you would retrieve the token.
*/
@Override
public void onNewToken(String token)
{
@ -19,36 +15,28 @@ public class FBMService extends FirebaseMessagingService
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// [START_EXCLUDE]
// There are two types of messages data messages and notification messages. Data messages are handled
// here in onMessageReceived whether the app is in the foreground or background. Data messages are the type
// traditionally used with GCM. Notification messages are only received here in onMessageReceived when the app
// is in the foreground. When the app is in the background an automatically generated notification is displayed.
// When the user taps on the notification they are returned to the app. Messages containing both notification
// and data payloads are treated as notification messages. The Firebase console always sends notification
// messages. For more see: https://firebase.google.com/docs/cloud-messaging/concept-options
// [END_EXCLUDE]
Log.i("FB::MessageReceived<0>", "");
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.i("FB::MessageReceived", "From: " + remoteMessage.getFrom());
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
public void onMessageReceived(RemoteMessage remoteMessage)
{
try
{
Log.i("FB::MessageReceived", "From: " + remoteMessage.getFrom());
Log.i("FB::MessageReceived", "Payload: " + remoteMessage.getData());
}
if (remoteMessage.getNotification() != null) Log.i("FB::MessageReceived", "Notify_Title: " + remoteMessage.getNotification().getTitle());
if (remoteMessage.getNotification() != null) Log.i("FB::MessageReceived", "Notify_Body: " + remoteMessage.getNotification().getBody());
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.i("FB::MessageReceived", "Notify_Title: " + remoteMessage.getNotification().getTitle());
Log.i("FB::MessageReceived", "Notify_Body: " + remoteMessage.getNotification().getBody());
}
long time = Long.parseLong(remoteMessage.getData().get("timestamp"));
String title = remoteMessage.getData().get("title");
String content = remoteMessage.getData().get("content");
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
CMessageList.inst().add(time, title, content);
SCNApp.showToast(title, Toast.LENGTH_LONG);
}
catch (Exception e)
{
Log.e("FB:Err", e.toString());
SCNApp.showToast("Recieved invalid message from server", Toast.LENGTH_LONG);
}
}
}
}

View File

@ -2,6 +2,8 @@ package com.blackforestbytes.simplecloudnotifier;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
@ -9,24 +11,25 @@ import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.InstanceIdResult;
public class MainActivity extends AppCompatActivity {
public class MainActivity extends AppCompatActivity
{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
@Override
public void onSuccess(InstanceIdResult instanceIdResult) {
Log.d("FB::ID", instanceIdResult.getId());
Log.d("FB::TOKEN", instanceIdResult.getToken());
}
});
}
});
RecyclerView rvMessages = findViewById(R.id.rvMessages);
rvMessages.setLayoutManager(new LinearLayoutManager(this, RecyclerView.VERTICAL, true));
rvMessages.setAdapter(new MessageAdapter());
SCNApp.register(this);
}
@Override
protected void onStop()
{
super.onStop();
CMessageList.inst().fullSave();
}
}

View File

@ -0,0 +1,72 @@
package com.blackforestbytes.simplecloudnotifier;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
public class MessageAdapter extends RecyclerView.Adapter
{
public MessageAdapter()
{
CMessageList.inst().register(this);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View myView = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_card, parent, false);
return new MessagePresenter(myView);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position)
{
CMessage msg = CMessageList.inst().tryGet(position);
MessagePresenter view = (MessagePresenter) holder;
view.setMessage(msg);
}
@Override
public int getItemCount()
{
return CMessageList.inst().size();
}
private class MessagePresenter extends RecyclerView.ViewHolder implements View.OnClickListener
{
private TextView tvTimestamp;
private TextView tvTitle;
private TextView tvMessage;
private CMessage data;
MessagePresenter(View itemView)
{
super(itemView);
tvTimestamp = itemView.findViewById(R.id.tvTimestamp);
tvTitle = itemView.findViewById(R.id.tvTitle);
tvMessage = itemView.findViewById(R.id.tvMessage);
itemView.setOnClickListener(this);
}
void setMessage(CMessage msg)
{
tvTimestamp.setText(msg.formatTimestamp());
tvTitle.setText(msg.Title);
tvMessage.setText(msg.Content);
data = msg;
}
@Override
public void onClick(View v)
{
SCNApp.showToast(data.Title, Toast.LENGTH_LONG);
}
}
}

View File

@ -0,0 +1,48 @@
package com.blackforestbytes.simplecloudnotifier;
import android.app.Application;
import android.content.Context;
import android.widget.Toast;
import java.lang.ref.WeakReference;
public class SCNApp extends Application
{
private static SCNApp instance;
private static WeakReference<MainActivity> mainActivity;
public SCNApp()
{
instance = this;
}
public static Context getContext()
{
return instance;
}
public static void showToast(final String msg, final int duration)
{
final MainActivity a = mainActivity.get();
if (a != null)
{
a.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(a, msg, duration).show();
}
});
}
}
public static boolean runOnUiThread(Runnable r)
{
final MainActivity a = mainActivity.get();
if (a != null) {a.runOnUiThread(r); return true;}
return false;
}
public static void register(MainActivity a)
{
mainActivity = new WeakReference<>(a);
}
}

View File

@ -1,29 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
tools:showIn="@layout/activity_main">
<TextView
android:layout_width="wrap_content"
<android.support.v7.widget.RecyclerView
android:id="@+id/rvMessages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:clipToPadding="false"
android:scrollbars="vertical" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Get ID"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</RelativeLayout>

View File

@ -0,0 +1,67 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/card_margin"
android:elevation="3dp"
card_view:cardCornerRadius="@dimen/card_album_radius">
<android.support.constraint.ConstraintLayout
android:background="@color/cardview_light_background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvTimestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textSize="12sp"
android:textStyle="italic"
android:text="2018-09-11 20:22:32" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tvTimestamp"
android:layout_marginRight="4sp"
android:layout_marginEnd="4sp"
android:textSize="16sp"
android:textColor="@color/colorBlack"
android:textStyle="bold"
android:ellipsize="none"
android:maxLines="6"
android:text="Message from me"/>
<TextView
android:id="@+id/tvMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tvTitle"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_margin="4sp"
android:ellipsize="none"
android:maxLines="32"
android:scrollHorizontally="false"
android:text="asdasd asdasd asd asd a" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View File

@ -3,4 +3,6 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorBlack">#000</color>
</resources>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="card_margin">5dp</dimen>
<dimen name="card_album_radius">0dp</dimen>
</resources>

View File

@ -9,8 +9,6 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath 'com.google.gms:google-services:4.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@ -44,6 +44,7 @@ $payload = json_encode(
[
'title' => $message,
'body' => $content,
'timestamp' => time(),
]
]);
$header=
@ -61,12 +62,8 @@ catch (Exception $e)
die(json_encode(['success' => false, 'message' => 'Exception: ' . $e->getMessage()]));
}
var_dump($httpresult);
$stmt = $pdo->prepare('UPDATE users SET timestamp_accessed=NOW(), messages_sent=messages_sent+1 WHERE user_id = :uid');
$stmt->execute(['uid' => $user_id]);
echo (json_encode(['success' => true, 'message' => 'Message sent']));
echo (json_encode(['success' => true, 'message' => 'Message sent', 'response' => $httpresult]));
return 0;